diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c	2013-12-19 12:21:25.947481248 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -409,29 +409,29 @@
     switch (lpMod -> surround) {
 
 
-      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 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;
+    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 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;
     }
 
     lpMod -> n   = compute_n(lpMod);
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c	2013-12-19 12:21:25.951481308 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -73,6 +73,7 @@
 #    define DIR_CHAR    '/'
 #endif
 
+
 // Symbols
 typedef enum {
 
@@ -143,6 +144,8 @@
 // Table. Each individual table can hold properties and rows & cols
 typedef struct _Table {
 
+        char SheetType[MAXSTR];               // The first row of the IT8 (the type)
+
         int            nSamples, nPatches;    // Cols, Rows
         int            SampleID;              // Pos of ID
 
@@ -162,7 +165,6 @@
 // This struct hold all information about an open IT8 handler.
 typedef struct {
 
-        char SheetType[MAXSTR];               // The first row of the IT8 (the type)
 
         cmsUInt32Number  TablesCount;                     // How many tables in this stream
         cmsUInt32Number  nTable;                          // The actual table
@@ -433,6 +435,8 @@
     return FALSE;
 }
 
+
+
 // Makes a file path based on a given reference path
 // NOTE: this function doesn't check if the path exists or even if it's legal
 static
@@ -574,7 +578,7 @@
     if (it8->ch == '.') {        // Decimal point
 
         cmsFloat64Number frac = 0.0;      // fraction
-        int prec = 0;           // precision
+        int prec = 0;                     // precision
 
         NextCh(it8);               // Eats dec. point
 
@@ -621,6 +625,81 @@
     }
 }
 
+// Parses a float number
+// This can not call directly atof because it uses locale dependant
+// parsing, while CCMX files always use . as decimal separator
+static
+cmsFloat64Number ParseFloatNumber(const char *Buffer)
+{
+    cmsFloat64Number dnum = 0.0;
+    int sign = 1;
+
+    if (*Buffer == '-' || *Buffer == '+') {
+
+         sign = (*Buffer == '-') ? -1 : 1;
+         Buffer++;
+    }
+
+
+    while (*Buffer && isdigit((int) *Buffer)) {
+
+        dnum = dnum * 10.0 + (*Buffer - '0');
+        if (*Buffer) Buffer++;
+    }
+
+    if (*Buffer == '.') {
+
+        cmsFloat64Number frac = 0.0;      // fraction
+        int prec = 0;                     // precission
+
+        if (*Buffer) Buffer++;
+
+        while (*Buffer && isdigit((int) *Buffer)) {
+
+            frac = frac * 10.0 + (*Buffer - '0');
+            prec++;
+            if (*Buffer) Buffer++;
+        }
+
+        dnum = dnum + (frac / xpow10(prec));
+    }
+
+    // Exponent, example 34.00E+20
+    if (*Buffer && toupper(*Buffer) == 'E') {
+
+        int e;
+        int sgn;
+
+        if (*Buffer) Buffer++;
+        sgn = 1;
+
+        if (*Buffer == '-') {
+
+            sgn = -1;
+            if (*Buffer) Buffer++;
+        }
+        else
+            if (*Buffer == '+') {
+
+                sgn = +1;
+                if (*Buffer) Buffer++;
+            }
+
+            e = 0;
+            while (*Buffer && isdigit((int) *Buffer)) {
+
+                if ((cmsFloat64Number) e * 10L < INT_MAX)
+                    e = e * 10 + (*Buffer - '0');
+
+                if (*Buffer) Buffer++;
+            }
+
+            e = sgn*e;
+            dnum = dnum * xpow10(e);
+    }
+
+    return sign * dnum;
+}
 
 
 // Reads next symbol
@@ -1011,7 +1090,7 @@
     cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used;
     cmsUInt8Number* ptr;
 
-    size = _cmsALIGNLONG(size);
+    size = _cmsALIGNMEM(size);
 
     if (size > Free) {
 
@@ -1212,7 +1291,7 @@
 cmsHANDLE  CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
 {
     cmsIT8* it8;
-    int i;
+    cmsUInt32Number i;
 
     it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8));
     if (it8 == NULL) return NULL;
@@ -1243,7 +1322,7 @@
     it8 -> lineno = 1;
 
     strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
-    strcpy(it8->SheetType, "CGATS.17");
+    cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17");
 
     // Initialize predefined properties & data
 
@@ -1260,18 +1339,15 @@
 
 const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8)
 {
-        cmsIT8* it8 = (cmsIT8*) hIT8;
-
-        return it8 ->SheetType;
-
+        return GetTable((cmsIT8*) hIT8)->SheetType;
 }
 
 cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type)
 {
-        cmsIT8* it8 = (cmsIT8*) hIT8;
+        TABLE* t = GetTable((cmsIT8*) hIT8);
 
-        strncpy(it8 ->SheetType, Type, MAXSTR-1);
-        it8 ->SheetType[MAXSTR-1] = 0;
+        strncpy(t ->SheetType, Type, MAXSTR-1);
+        t ->SheetType[MAXSTR-1] = 0;
         return TRUE;
 }
 
@@ -1285,8 +1361,6 @@
     return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL;
 }
 
-
-
 // Sets a property
 cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val)
 {
@@ -1298,7 +1372,6 @@
     return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL;
 }
 
-
 cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val)
 {
     cmsIT8* it8 = (cmsIT8*) hIT8;
@@ -1351,8 +1424,7 @@
 {
     const char *v = cmsIT8GetProperty(hIT8, cProp);
 
-    if (v) return atof(v);
-    else return 0.0;
+    return ParseFloatNumber(v);
 }
 
 const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey)
@@ -1553,6 +1625,9 @@
     KEYVALUE* p;
     TABLE* t = GetTable(it8);
 
+    // Writes the type
+    WriteStr(fp, t->SheetType);
+    WriteStr(fp, "\n");
 
     for (p = t->HeaderList; (p != NULL); p = p->Next)
     {
@@ -1701,8 +1776,6 @@
     sd.stream = fopen(cFileName, "wt");
     if (!sd.stream) return FALSE;
 
-    WriteStr(&sd, it8->SheetType);
-    WriteStr(&sd, "\n");
     for (i=0; i < it8 ->TablesCount; i++) {
 
             cmsIT8SetTable(hIT8, i);
@@ -1737,20 +1810,18 @@
     else
         sd.Max  = 0;                // Just counting the needed bytes
 
-    WriteStr(&sd, it8->SheetType);
-    WriteStr(&sd, "\n");
     for (i=0; i < it8 ->TablesCount; i++) {
 
-            cmsIT8SetTable(hIT8, i);
-            WriteHeader(it8, &sd);
-            WriteDataFormat(&sd, it8);
-            WriteData(&sd, it8);
+        cmsIT8SetTable(hIT8, i);
+        WriteHeader(it8, &sd);
+        WriteDataFormat(&sd, it8);
+        WriteData(&sd, it8);
     }
 
     sd.Used++;  // The \0 at the very end
 
     if (sd.Base)
-        sd.Ptr = 0;
+        *sd.Ptr = 0;
 
     *BytesNeeded = sd.Used;
 
@@ -1963,12 +2034,8 @@
 
 
 static
-cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
+void ReadType(cmsIT8* it8, char* SheetTypePtr)
 {
-    char* SheetTypePtr = it8 ->SheetType;
-
-    if (nosheet == 0) {
-
     // First line is a very special case.
 
     while (isseparator(it8->ch))
@@ -1979,9 +2046,20 @@
         *SheetTypePtr++= (char) it8 ->ch;
         NextCh(it8);
     }
-    }
 
     *SheetTypePtr = 0;
+}
+
+
+static
+cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
+{
+    char* SheetTypePtr = it8 ->Tab[0].SheetType;
+
+    if (nosheet == 0) {
+        ReadType(it8, SheetTypePtr);
+    }
+
     InSymbol(it8);
 
     SkipEOLN(it8);
@@ -2003,6 +2081,39 @@
 
                             AllocTable(it8);
                             it8 ->nTable = it8 ->TablesCount - 1;
+
+                            // Read sheet type if present. We only support identifier and string.
+                            // <ident> <eoln> is a type string
+                            // anything else, is not a type string
+                            if (nosheet == 0) {
+
+                                if (it8 ->sy == SIDENT) {
+
+                                    // May be a type sheet or may be a prop value statement. We cannot use insymbol in
+                                    // this special case...
+                                     while (isseparator(it8->ch))
+                                         NextCh(it8);
+
+                                     // If a newline is found, then this is a type string
+                                    if (it8 ->ch == '\n') {
+
+                                         cmsIT8SetSheetType(it8, it8 ->id);
+                                         InSymbol(it8);
+                                    }
+                                    else
+                                    {
+                                        // It is not. Just continue
+                                        cmsIT8SetSheetType(it8, "");
+                                    }
+                                }
+                                else
+                                    // Validate quoted strings
+                                    if (it8 ->sy == SSTRING) {
+                                        cmsIT8SetSheetType(it8, it8 ->str);
+                                        InSymbol(it8);
+                                    }
+                           }
+
                     }
                     break;
 
@@ -2123,14 +2234,14 @@
 
 // Try to infere if the file is a CGATS/IT8 file at all. Read first line
 // that should be something like some printable characters plus a \n
-
+// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line?
 static
 int IsMyBlock(cmsUInt8Number* Buffer, int n)
 {
-    int cols = 1, space = 0, quot = 0;
+    int words = 1, space = 0, quot = 0;
     int i;
 
-    if (n < 10) return FALSE;   // Too small
+    if (n < 10) return 0;   // Too small
 
     if (n > 132)
         n = 132;
@@ -2141,7 +2252,7 @@
         {
         case '\n':
         case '\r':
-            return quot == 1 || cols > 2 ? 0 : cols;
+            return ((quot == 1) || (words > 2)) ? 0 : words;
         case '\t':
         case ' ':
             if(!quot && !space)
@@ -2153,14 +2264,13 @@
         default:
             if (Buffer[i] < 32) return 0;
             if (Buffer[i] > 127) return 0;
-            cols += space;
+            words += space;
             space = 0;
             break;
         }
     }
 
-    return FALSE;
-
+    return 0;
 }
 
 
@@ -2271,7 +2381,7 @@
     it8 ->nTable = 0;
 
     if (fclose(it8 ->FileStack[0]->Stream)!= 0) {
-        cmsIT8Free(hIT8);
+            cmsIT8Free(hIT8);
             return NULL;
     }
 
@@ -2454,13 +2564,7 @@
 
     Buffer = cmsIT8GetDataRowCol(hIT8, row, col);
 
-    if (Buffer) {
-
-        return atof(Buffer);
-
-    } else
-        return 0;
-
+    return ParseFloatNumber(Buffer);
 }
 
 
@@ -2515,14 +2619,7 @@
 
     Buffer = cmsIT8GetData(it8, cPatch, cSample);
 
-    if (Buffer) {
-
-        return atof(Buffer);
-
-    } else {
-
-        return 0;
-    }
+    return ParseFloatNumber(Buffer);
 }
 
 
@@ -2680,5 +2777,7 @@
         strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
     else
         strcpy(it8->DoubleFormatter, Formatter);
+
+    it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
 }
 
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c	2013-12-19 12:21:25.959481430 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -193,17 +193,21 @@
 static
 cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad)
 {
-    // Convert D50 across CHAD to get the absolute white point
-     cmsVEC3 d, s;
-     cmsCIEXYZ Dest;
-     cmsCIExyY DestChromaticity;
-     cmsFloat64Number TempK;
+    // Convert D50 across inverse CHAD to get the absolute white point
+    cmsVEC3 d, s;
+    cmsCIEXYZ Dest;
+    cmsCIExyY DestChromaticity;
+    cmsFloat64Number TempK;
+    cmsMAT3 m1, m2;
+
+    m1 = *Chad;
+    if (!_cmsMAT3inverse(&m1, &m2)) return FALSE;
 
     s.n[VX] = cmsD50_XYZ() -> X;
     s.n[VY] = cmsD50_XYZ() -> Y;
     s.n[VZ] = cmsD50_XYZ() -> Z;
 
-    _cmsMAT3eval(&d, Chad, &s);
+    _cmsMAT3eval(&d, &m2, &s);
 
     Dest.X = d.n[VX];
     Dest.Y = d.n[VY];
@@ -219,15 +223,14 @@
 
 // Compute a CHAD based on a given temperature
 static
-void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
+    void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
 {
     cmsCIEXYZ White;
     cmsCIExyY ChromaticityOfWhite;
 
     cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp);
     cmsxyY2XYZ(&White, &ChromaticityOfWhite);
-    _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White);
-
+    _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ());
 }
 
 // Join scalings to obtain relative input to absolute and then to relative output.
@@ -240,7 +243,7 @@
                                const cmsMAT3* ChromaticAdaptationMatrixOut,
                                cmsMAT3* m)
 {
-    cmsMAT3 Scale, m1, m2, m3;
+    cmsMAT3 Scale, m1, m2, m3, m4;
 
     // Adaptation state
     if (AdaptationState == 1.0) {
@@ -259,23 +262,32 @@
         _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) {
 
+            m1 = *ChromaticAdaptationMatrixOut;
+            _cmsMAT3per(&m2, &m1, &Scale);
+            // m2 holds CHAD from output white to D50 times abs. col. scaling
+
             // Observer is not adapted, undo the chromatic adaptation
             _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut);
 
+            m3 = *ChromaticAdaptationMatrixIn;
+            if (!_cmsMAT3inverse(&m3, &m4)) return FALSE;
+            _cmsMAT3per(m, &m2, &m4);
+
         } else {
 
             cmsMAT3 MixedCHAD;
             cmsFloat64Number TempSrc, TempDest, Temp;
 
-            TempSrc  = CHAD2Temp(ChromaticAdaptationMatrixIn);  // K for source white
-            TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white
+            m1 = *ChromaticAdaptationMatrixIn;
+            if (!_cmsMAT3inverse(&m1, &m2)) return FALSE;
+            _cmsMAT3per(&m3, &m2, &Scale);
+            // m3 holds CHAD from input white to D50 times abs. col. scaling
+
+            TempSrc  = CHAD2Temp(ChromaticAdaptationMatrixIn);
+            TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut);
 
             if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong
 
@@ -285,9 +297,9 @@
                 return TRUE;
             }
 
-            Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest;
+            Temp = (1.0 - AdaptationState) * TempDest + AdaptationState * TempSrc;
 
-            // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD
+            // Get a CHAD from whatever output temperature to D50. This replaces output CHAD
             Temp2CHAD(&MixedCHAD, Temp);
 
             _cmsMAT3per(m, &m3, &MixedCHAD);
@@ -362,7 +374,7 @@
             cmsCIEXYZ BlackPointIn, BlackPointOut;
 
             cmsDetectBlackPoint(&BlackPointIn,  hProfiles[i-1], Intent, 0);
-            cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0);
+            cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0);
 
             // If black points are equal, then do nothing
             if (BlackPointIn.X != BlackPointOut.X ||
@@ -463,6 +475,10 @@
     // If they are same, they are compatible.
     if (a == b) return TRUE;
 
+    // Check for MCH4 substitution of CMYK
+    if ((a == cmsSig4colorData) && (b == cmsSigCmykData)) return TRUE;
+    if ((a == cmsSigCmykData) && (b == cmsSig4colorData)) return TRUE;
+
     // 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;
@@ -511,7 +527,7 @@
             lIsInput = TRUE;
         }
         else {
-            // Else use profile in the input direction if current space is not PCS
+          // Else use profile in the input direction if current space is not PCS
         lIsInput      = (CurrentColorSpace != cmsSigXYZData) &&
                         (CurrentColorSpace != cmsSigLabData);
         }
@@ -537,7 +553,7 @@
 
         // 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) {
+        if (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) {
 
             // Get the involved LUT from the profile
             Lut = _cmsReadDevicelinkLUT(hProfile, Intent);
@@ -876,7 +892,8 @@
 
     // Check for non-cmyk profiles
     if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
-        cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData)
+        !(cmsGetColorSpace(hProfiles[nProfiles-1]) == cmsSigCmykData ||
+        cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigOutputClass))
            return  DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
 
     // Allocate an empty LUT for holding the result
@@ -893,6 +910,8 @@
 
     // Get total area coverage (in 0..1 domain)
     bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0;
+    if (bp.MaxTAC <= 0) goto Cleanup;
+
 
     // Create a LUT holding normal ICC transform
     bp.cmyk2cmyk = DefaultICCintents(ContextID,
@@ -902,6 +921,7 @@
                                          BPC,
                                          AdaptationStates,
                                          dwFlags);
+    if (bp.cmyk2cmyk == NULL) goto Cleanup;
 
     // Now the tone curve
     bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles,
@@ -910,7 +930,7 @@
                                    BPC,
                                    AdaptationStates,
                                    dwFlags);
-
+    if (bp.KTone == NULL) goto Cleanup;
 
     // To measure the output, Last profile to Lab
     hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
@@ -918,6 +938,7 @@
                                          CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL,
                                          INTENT_RELATIVE_COLORIMETRIC,
                                          cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
+    if ( bp.hProofOutput == NULL) goto Cleanup;
 
     // Same as anterior, but lab in the 0..1 range
     bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
@@ -925,6 +946,7 @@
                                          FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4),
                                          INTENT_RELATIVE_COLORIMETRIC,
                                          cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
+    if (bp.cmyk2Lab == NULL) goto Cleanup;
     cmsCloseProfile(hLab);
 
     // Error estimation (for debug only)
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c	2013-12-19 12:21:25.959481430 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -72,17 +72,21 @@
 // long int because C99 specifies ftell in such way (7.19.9.2)
 long int CMSEXPORT cmsfilelength(FILE* f)
 {
-    long int n;
+    long int p , n;
+
+    p = ftell(f); // register current file position
 
     if (fseek(f, 0, SEEK_END) != 0) {
         return -1;
     }
+
     n = ftell(f);
-    fseek(f, 0, SEEK_SET);
+    fseek(f, p, SEEK_SET); // file position restored
 
     return n;
 }
 
+
 // Memory handling ------------------------------------------------------------------
 //
 // This is the interface to low-level memory management routines. By default a simple
@@ -160,6 +164,12 @@
 {
     cmsUInt32Number Total = num * size;
 
+    // Preserve calloc behaviour
+    if (Total == 0) return NULL;
+
+    // Safe check for overflow.
+    if (num >= UINT_MAX / size) return NULL;
+
     // Check for overflow
     if (Total < num || Total < size) {
         return NULL;
@@ -269,12 +279,16 @@
 // 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)
+// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)
 static
 _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
 {
     _cmsSubAllocator_chunk* chunk;
 
+    // 20K by default
+    if (Initial == 0)
+        Initial = 20*1024;
+
     // Create the container
     chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk));
     if (chunk == NULL) return NULL;
@@ -288,9 +302,7 @@
         return NULL;
     }
 
-    // 20K by default
-    if (Initial == 0)
-        Initial = 20*1024;
+
 
     chunk ->BlockSize = Initial;
     chunk ->Used      = 0;
@@ -344,7 +356,7 @@
     cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used;
     cmsUInt8Number* ptr;
 
-    size = _cmsALIGNLONG(size);
+    size = _cmsALIGNMEM(size);
 
     // Check for memory. If there is no room, allocate a new chunk of double memory size.
     if (size > Free) {
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c	2013-12-19 12:21:25.959481430 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -277,18 +277,28 @@
 
     switch (Type) {
 
-    // X = Y ^ Gamma
+   // X = Y ^ Gamma
     case 1:
-        if (R < 0)
-            Val = 0;
+        if (R < 0) {
+
+            if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
+                Val = R;
+            else
+                Val = 0;
+        }
         else
             Val = pow(R, Params[0]);
         break;
 
     // Type 1 Reversed: X = Y ^1/gamma
     case -1:
-        if (R < 0)
-            Val = 0;
+         if (R < 0) {
+
+            if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
+                Val = R;
+            else
+                Val = 0;
+        }
         else
             Val = pow(R, 1/Params[0]);
         break;
@@ -552,6 +562,19 @@
     return MINUS_INF;
 }
 
+// Access to estimated low-res table
+cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t)
+{
+    _cmsAssert(t != NULL);
+    return t ->nEntries;
+}
+
+const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t)
+{
+    _cmsAssert(t != NULL);
+    return t ->Table16;
+}
+
 
 // Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
 // floating point description empty.
@@ -828,7 +851,7 @@
 cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve)
 {
     cmsToneCurve *out;
-    cmsFloat64Number a = 1, b = 0, y, x1, y1, x2, y2;
+    cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2;
     int i, j;
     int Ascending;
 
@@ -859,6 +882,7 @@
         j = GetInterval(y, InCurve->Table16, InCurve->InterpParams);
         if (j >= 0) {
 
+
             // Get limits of interval
             x1 = InCurve ->Table16[j];
             x2 = InCurve ->Table16[j+1];
@@ -883,6 +907,7 @@
         out ->Table16[i] = _cmsQuickSaturateWord(a* y + b);
     }
 
+
     return out;
 }
 
@@ -891,7 +916,7 @@
 {
     _cmsAssert(InGamma != NULL);
 
-    return cmsReverseToneCurveEx(InGamma -> nEntries, InGamma);
+    return cmsReverseToneCurveEx(4096, InGamma);
 }
 
 // From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite
@@ -1035,20 +1060,42 @@
 {
     int n;
     int i, last;
+    cmsBool lDescending;
 
     _cmsAssert(t != NULL);
 
-    n    = t ->nEntries;
-    last = t ->Table16[n-1];
+    // Degenerated curves are monotonic? Ok, let's pass them
+    n = t ->nEntries;
+    if (n < 2) return TRUE;
 
-    for (i = n-2; i >= 0; --i) {
+    // Curve direction
+    lDescending = cmsIsToneCurveDescending(t);
 
-        if (t ->Table16[i] > last)
+    if (lDescending) {
 
-            return FALSE;
-        else
-            last = t ->Table16[i];
+        last = t ->Table16[0];
+
+        for (i = 1; i < n; i++) {
 
+            if (t ->Table16[i] - last > 2) // We allow some ripple
+                return FALSE;
+            else
+                last = t ->Table16[i];
+
+        }
+    }
+    else {
+
+        last = t ->Table16[n-1];
+
+        for (i = n-2; i >= 0; --i) {
+
+            if (t ->Table16[i] - last > 2)
+                return FALSE;
+            else
+                last = t ->Table16[i];
+
+        }
     }
 
     return TRUE;
@@ -1163,4 +1210,3 @@
 
     return (sum / n);   // The mean
 }
-
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c	2013-12-19 12:21:25.959481430 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -212,7 +212,6 @@
 
     // Make sure it is monotonic
     if (!cmsIsToneCurveMonotonic(KTone)) {
-
         cmsFreeToneCurve(KTone);
         return NULL;
     }
@@ -246,7 +245,7 @@
     GAMUTCHAIN*  t = (GAMUTCHAIN* ) Cargo;
     cmsCIELab LabIn1, LabOut1;
     cmsCIELab LabIn2, LabOut2;
-    cmsFloat32Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
+    cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
     cmsFloat64Number dE1, dE2, ErrorRatio;
 
     // Assume in-gamut by default.
@@ -396,8 +395,8 @@
                                               cmsFLAGS_NOCACHE);
 
 
-    // Does create the forward step. Lab double to cmsFloat32Number
-    dwFormat    = (FLOAT_SH(1)|CHANNELS_SH(nChannels)|BYTES_SH(4));
+    // Does create the forward step. Lab double to device
+    dwFormat    = (CHANNELS_SH(nChannels)|BYTES_SH(2));
     Chain.hForward = cmsCreateTransformTHR(ContextID,
                                            hLab, TYPE_Lab_DBL,
                                            hGamut, dwFormat,
@@ -421,10 +420,10 @@
 
         if (Gamut != NULL) {
 
-            CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
-            cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT);
+          CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
+          cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT);
 
-            cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
+          cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
         }
     }
     else
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c	1970-01-01 01:00:00.000000000 +0100
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c	2013-12-19 12:23:00.748901273 +0000
@@ -0,0 +1,564 @@
+/*
+ * 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 Color Management System
+//  Copyright (c) 1998-2012 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"),
+// 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 "lcms2_internal.h"
+
+#ifndef CMS_NO_HALF_SUPPORT
+
+// This code is inspired in the paper "Fast Half Float Conversions"
+// by Jeroen van der Zijp
+
+static cmsUInt32Number Mantissa[2048] = {
+
+0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34a00000,
+0x34c00000, 0x34e00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000,
+0x35400000, 0x35500000, 0x35600000, 0x35700000, 0x35800000, 0x35880000,
+0x35900000, 0x35980000, 0x35a00000, 0x35a80000, 0x35b00000, 0x35b80000,
+0x35c00000, 0x35c80000, 0x35d00000, 0x35d80000, 0x35e00000, 0x35e80000,
+0x35f00000, 0x35f80000, 0x36000000, 0x36040000, 0x36080000, 0x360c0000,
+0x36100000, 0x36140000, 0x36180000, 0x361c0000, 0x36200000, 0x36240000,
+0x36280000, 0x362c0000, 0x36300000, 0x36340000, 0x36380000, 0x363c0000,
+0x36400000, 0x36440000, 0x36480000, 0x364c0000, 0x36500000, 0x36540000,
+0x36580000, 0x365c0000, 0x36600000, 0x36640000, 0x36680000, 0x366c0000,
+0x36700000, 0x36740000, 0x36780000, 0x367c0000, 0x36800000, 0x36820000,
+0x36840000, 0x36860000, 0x36880000, 0x368a0000, 0x368c0000, 0x368e0000,
+0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369a0000,
+0x369c0000, 0x369e0000, 0x36a00000, 0x36a20000, 0x36a40000, 0x36a60000,
+0x36a80000, 0x36aa0000, 0x36ac0000, 0x36ae0000, 0x36b00000, 0x36b20000,
+0x36b40000, 0x36b60000, 0x36b80000, 0x36ba0000, 0x36bc0000, 0x36be0000,
+0x36c00000, 0x36c20000, 0x36c40000, 0x36c60000, 0x36c80000, 0x36ca0000,
+0x36cc0000, 0x36ce0000, 0x36d00000, 0x36d20000, 0x36d40000, 0x36d60000,
+0x36d80000, 0x36da0000, 0x36dc0000, 0x36de0000, 0x36e00000, 0x36e20000,
+0x36e40000, 0x36e60000, 0x36e80000, 0x36ea0000, 0x36ec0000, 0x36ee0000,
+0x36f00000, 0x36f20000, 0x36f40000, 0x36f60000, 0x36f80000, 0x36fa0000,
+0x36fc0000, 0x36fe0000, 0x37000000, 0x37010000, 0x37020000, 0x37030000,
+0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000,
+0x370a0000, 0x370b0000, 0x370c0000, 0x370d0000, 0x370e0000, 0x370f0000,
+0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000,
+0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371a0000, 0x371b0000,
+0x371c0000, 0x371d0000, 0x371e0000, 0x371f0000, 0x37200000, 0x37210000,
+0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000,
+0x37280000, 0x37290000, 0x372a0000, 0x372b0000, 0x372c0000, 0x372d0000,
+0x372e0000, 0x372f0000, 0x37300000, 0x37310000, 0x37320000, 0x37330000,
+0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000,
+0x373a0000, 0x373b0000, 0x373c0000, 0x373d0000, 0x373e0000, 0x373f0000,
+0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000,
+0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374a0000, 0x374b0000,
+0x374c0000, 0x374d0000, 0x374e0000, 0x374f0000, 0x37500000, 0x37510000,
+0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000,
+0x37580000, 0x37590000, 0x375a0000, 0x375b0000, 0x375c0000, 0x375d0000,
+0x375e0000, 0x375f0000, 0x37600000, 0x37610000, 0x37620000, 0x37630000,
+0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000,
+0x376a0000, 0x376b0000, 0x376c0000, 0x376d0000, 0x376e0000, 0x376f0000,
+0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000,
+0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377a0000, 0x377b0000,
+0x377c0000, 0x377d0000, 0x377e0000, 0x377f0000, 0x37800000, 0x37808000,
+0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000,
+0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000,
+0x37870000, 0x37878000, 0x37880000, 0x37888000, 0x37890000, 0x37898000,
+0x378a0000, 0x378a8000, 0x378b0000, 0x378b8000, 0x378c0000, 0x378c8000,
+0x378d0000, 0x378d8000, 0x378e0000, 0x378e8000, 0x378f0000, 0x378f8000,
+0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000,
+0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000,
+0x37960000, 0x37968000, 0x37970000, 0x37978000, 0x37980000, 0x37988000,
+0x37990000, 0x37998000, 0x379a0000, 0x379a8000, 0x379b0000, 0x379b8000,
+0x379c0000, 0x379c8000, 0x379d0000, 0x379d8000, 0x379e0000, 0x379e8000,
+0x379f0000, 0x379f8000, 0x37a00000, 0x37a08000, 0x37a10000, 0x37a18000,
+0x37a20000, 0x37a28000, 0x37a30000, 0x37a38000, 0x37a40000, 0x37a48000,
+0x37a50000, 0x37a58000, 0x37a60000, 0x37a68000, 0x37a70000, 0x37a78000,
+0x37a80000, 0x37a88000, 0x37a90000, 0x37a98000, 0x37aa0000, 0x37aa8000,
+0x37ab0000, 0x37ab8000, 0x37ac0000, 0x37ac8000, 0x37ad0000, 0x37ad8000,
+0x37ae0000, 0x37ae8000, 0x37af0000, 0x37af8000, 0x37b00000, 0x37b08000,
+0x37b10000, 0x37b18000, 0x37b20000, 0x37b28000, 0x37b30000, 0x37b38000,
+0x37b40000, 0x37b48000, 0x37b50000, 0x37b58000, 0x37b60000, 0x37b68000,
+0x37b70000, 0x37b78000, 0x37b80000, 0x37b88000, 0x37b90000, 0x37b98000,
+0x37ba0000, 0x37ba8000, 0x37bb0000, 0x37bb8000, 0x37bc0000, 0x37bc8000,
+0x37bd0000, 0x37bd8000, 0x37be0000, 0x37be8000, 0x37bf0000, 0x37bf8000,
+0x37c00000, 0x37c08000, 0x37c10000, 0x37c18000, 0x37c20000, 0x37c28000,
+0x37c30000, 0x37c38000, 0x37c40000, 0x37c48000, 0x37c50000, 0x37c58000,
+0x37c60000, 0x37c68000, 0x37c70000, 0x37c78000, 0x37c80000, 0x37c88000,
+0x37c90000, 0x37c98000, 0x37ca0000, 0x37ca8000, 0x37cb0000, 0x37cb8000,
+0x37cc0000, 0x37cc8000, 0x37cd0000, 0x37cd8000, 0x37ce0000, 0x37ce8000,
+0x37cf0000, 0x37cf8000, 0x37d00000, 0x37d08000, 0x37d10000, 0x37d18000,
+0x37d20000, 0x37d28000, 0x37d30000, 0x37d38000, 0x37d40000, 0x37d48000,
+0x37d50000, 0x37d58000, 0x37d60000, 0x37d68000, 0x37d70000, 0x37d78000,
+0x37d80000, 0x37d88000, 0x37d90000, 0x37d98000, 0x37da0000, 0x37da8000,
+0x37db0000, 0x37db8000, 0x37dc0000, 0x37dc8000, 0x37dd0000, 0x37dd8000,
+0x37de0000, 0x37de8000, 0x37df0000, 0x37df8000, 0x37e00000, 0x37e08000,
+0x37e10000, 0x37e18000, 0x37e20000, 0x37e28000, 0x37e30000, 0x37e38000,
+0x37e40000, 0x37e48000, 0x37e50000, 0x37e58000, 0x37e60000, 0x37e68000,
+0x37e70000, 0x37e78000, 0x37e80000, 0x37e88000, 0x37e90000, 0x37e98000,
+0x37ea0000, 0x37ea8000, 0x37eb0000, 0x37eb8000, 0x37ec0000, 0x37ec8000,
+0x37ed0000, 0x37ed8000, 0x37ee0000, 0x37ee8000, 0x37ef0000, 0x37ef8000,
+0x37f00000, 0x37f08000, 0x37f10000, 0x37f18000, 0x37f20000, 0x37f28000,
+0x37f30000, 0x37f38000, 0x37f40000, 0x37f48000, 0x37f50000, 0x37f58000,
+0x37f60000, 0x37f68000, 0x37f70000, 0x37f78000, 0x37f80000, 0x37f88000,
+0x37f90000, 0x37f98000, 0x37fa0000, 0x37fa8000, 0x37fb0000, 0x37fb8000,
+0x37fc0000, 0x37fc8000, 0x37fd0000, 0x37fd8000, 0x37fe0000, 0x37fe8000,
+0x37ff0000, 0x37ff8000, 0x38000000, 0x38004000, 0x38008000, 0x3800c000,
+0x38010000, 0x38014000, 0x38018000, 0x3801c000, 0x38020000, 0x38024000,
+0x38028000, 0x3802c000, 0x38030000, 0x38034000, 0x38038000, 0x3803c000,
+0x38040000, 0x38044000, 0x38048000, 0x3804c000, 0x38050000, 0x38054000,
+0x38058000, 0x3805c000, 0x38060000, 0x38064000, 0x38068000, 0x3806c000,
+0x38070000, 0x38074000, 0x38078000, 0x3807c000, 0x38080000, 0x38084000,
+0x38088000, 0x3808c000, 0x38090000, 0x38094000, 0x38098000, 0x3809c000,
+0x380a0000, 0x380a4000, 0x380a8000, 0x380ac000, 0x380b0000, 0x380b4000,
+0x380b8000, 0x380bc000, 0x380c0000, 0x380c4000, 0x380c8000, 0x380cc000,
+0x380d0000, 0x380d4000, 0x380d8000, 0x380dc000, 0x380e0000, 0x380e4000,
+0x380e8000, 0x380ec000, 0x380f0000, 0x380f4000, 0x380f8000, 0x380fc000,
+0x38100000, 0x38104000, 0x38108000, 0x3810c000, 0x38110000, 0x38114000,
+0x38118000, 0x3811c000, 0x38120000, 0x38124000, 0x38128000, 0x3812c000,
+0x38130000, 0x38134000, 0x38138000, 0x3813c000, 0x38140000, 0x38144000,
+0x38148000, 0x3814c000, 0x38150000, 0x38154000, 0x38158000, 0x3815c000,
+0x38160000, 0x38164000, 0x38168000, 0x3816c000, 0x38170000, 0x38174000,
+0x38178000, 0x3817c000, 0x38180000, 0x38184000, 0x38188000, 0x3818c000,
+0x38190000, 0x38194000, 0x38198000, 0x3819c000, 0x381a0000, 0x381a4000,
+0x381a8000, 0x381ac000, 0x381b0000, 0x381b4000, 0x381b8000, 0x381bc000,
+0x381c0000, 0x381c4000, 0x381c8000, 0x381cc000, 0x381d0000, 0x381d4000,
+0x381d8000, 0x381dc000, 0x381e0000, 0x381e4000, 0x381e8000, 0x381ec000,
+0x381f0000, 0x381f4000, 0x381f8000, 0x381fc000, 0x38200000, 0x38204000,
+0x38208000, 0x3820c000, 0x38210000, 0x38214000, 0x38218000, 0x3821c000,
+0x38220000, 0x38224000, 0x38228000, 0x3822c000, 0x38230000, 0x38234000,
+0x38238000, 0x3823c000, 0x38240000, 0x38244000, 0x38248000, 0x3824c000,
+0x38250000, 0x38254000, 0x38258000, 0x3825c000, 0x38260000, 0x38264000,
+0x38268000, 0x3826c000, 0x38270000, 0x38274000, 0x38278000, 0x3827c000,
+0x38280000, 0x38284000, 0x38288000, 0x3828c000, 0x38290000, 0x38294000,
+0x38298000, 0x3829c000, 0x382a0000, 0x382a4000, 0x382a8000, 0x382ac000,
+0x382b0000, 0x382b4000, 0x382b8000, 0x382bc000, 0x382c0000, 0x382c4000,
+0x382c8000, 0x382cc000, 0x382d0000, 0x382d4000, 0x382d8000, 0x382dc000,
+0x382e0000, 0x382e4000, 0x382e8000, 0x382ec000, 0x382f0000, 0x382f4000,
+0x382f8000, 0x382fc000, 0x38300000, 0x38304000, 0x38308000, 0x3830c000,
+0x38310000, 0x38314000, 0x38318000, 0x3831c000, 0x38320000, 0x38324000,
+0x38328000, 0x3832c000, 0x38330000, 0x38334000, 0x38338000, 0x3833c000,
+0x38340000, 0x38344000, 0x38348000, 0x3834c000, 0x38350000, 0x38354000,
+0x38358000, 0x3835c000, 0x38360000, 0x38364000, 0x38368000, 0x3836c000,
+0x38370000, 0x38374000, 0x38378000, 0x3837c000, 0x38380000, 0x38384000,
+0x38388000, 0x3838c000, 0x38390000, 0x38394000, 0x38398000, 0x3839c000,
+0x383a0000, 0x383a4000, 0x383a8000, 0x383ac000, 0x383b0000, 0x383b4000,
+0x383b8000, 0x383bc000, 0x383c0000, 0x383c4000, 0x383c8000, 0x383cc000,
+0x383d0000, 0x383d4000, 0x383d8000, 0x383dc000, 0x383e0000, 0x383e4000,
+0x383e8000, 0x383ec000, 0x383f0000, 0x383f4000, 0x383f8000, 0x383fc000,
+0x38400000, 0x38404000, 0x38408000, 0x3840c000, 0x38410000, 0x38414000,
+0x38418000, 0x3841c000, 0x38420000, 0x38424000, 0x38428000, 0x3842c000,
+0x38430000, 0x38434000, 0x38438000, 0x3843c000, 0x38440000, 0x38444000,
+0x38448000, 0x3844c000, 0x38450000, 0x38454000, 0x38458000, 0x3845c000,
+0x38460000, 0x38464000, 0x38468000, 0x3846c000, 0x38470000, 0x38474000,
+0x38478000, 0x3847c000, 0x38480000, 0x38484000, 0x38488000, 0x3848c000,
+0x38490000, 0x38494000, 0x38498000, 0x3849c000, 0x384a0000, 0x384a4000,
+0x384a8000, 0x384ac000, 0x384b0000, 0x384b4000, 0x384b8000, 0x384bc000,
+0x384c0000, 0x384c4000, 0x384c8000, 0x384cc000, 0x384d0000, 0x384d4000,
+0x384d8000, 0x384dc000, 0x384e0000, 0x384e4000, 0x384e8000, 0x384ec000,
+0x384f0000, 0x384f4000, 0x384f8000, 0x384fc000, 0x38500000, 0x38504000,
+0x38508000, 0x3850c000, 0x38510000, 0x38514000, 0x38518000, 0x3851c000,
+0x38520000, 0x38524000, 0x38528000, 0x3852c000, 0x38530000, 0x38534000,
+0x38538000, 0x3853c000, 0x38540000, 0x38544000, 0x38548000, 0x3854c000,
+0x38550000, 0x38554000, 0x38558000, 0x3855c000, 0x38560000, 0x38564000,
+0x38568000, 0x3856c000, 0x38570000, 0x38574000, 0x38578000, 0x3857c000,
+0x38580000, 0x38584000, 0x38588000, 0x3858c000, 0x38590000, 0x38594000,
+0x38598000, 0x3859c000, 0x385a0000, 0x385a4000, 0x385a8000, 0x385ac000,
+0x385b0000, 0x385b4000, 0x385b8000, 0x385bc000, 0x385c0000, 0x385c4000,
+0x385c8000, 0x385cc000, 0x385d0000, 0x385d4000, 0x385d8000, 0x385dc000,
+0x385e0000, 0x385e4000, 0x385e8000, 0x385ec000, 0x385f0000, 0x385f4000,
+0x385f8000, 0x385fc000, 0x38600000, 0x38604000, 0x38608000, 0x3860c000,
+0x38610000, 0x38614000, 0x38618000, 0x3861c000, 0x38620000, 0x38624000,
+0x38628000, 0x3862c000, 0x38630000, 0x38634000, 0x38638000, 0x3863c000,
+0x38640000, 0x38644000, 0x38648000, 0x3864c000, 0x38650000, 0x38654000,
+0x38658000, 0x3865c000, 0x38660000, 0x38664000, 0x38668000, 0x3866c000,
+0x38670000, 0x38674000, 0x38678000, 0x3867c000, 0x38680000, 0x38684000,
+0x38688000, 0x3868c000, 0x38690000, 0x38694000, 0x38698000, 0x3869c000,
+0x386a0000, 0x386a4000, 0x386a8000, 0x386ac000, 0x386b0000, 0x386b4000,
+0x386b8000, 0x386bc000, 0x386c0000, 0x386c4000, 0x386c8000, 0x386cc000,
+0x386d0000, 0x386d4000, 0x386d8000, 0x386dc000, 0x386e0000, 0x386e4000,
+0x386e8000, 0x386ec000, 0x386f0000, 0x386f4000, 0x386f8000, 0x386fc000,
+0x38700000, 0x38704000, 0x38708000, 0x3870c000, 0x38710000, 0x38714000,
+0x38718000, 0x3871c000, 0x38720000, 0x38724000, 0x38728000, 0x3872c000,
+0x38730000, 0x38734000, 0x38738000, 0x3873c000, 0x38740000, 0x38744000,
+0x38748000, 0x3874c000, 0x38750000, 0x38754000, 0x38758000, 0x3875c000,
+0x38760000, 0x38764000, 0x38768000, 0x3876c000, 0x38770000, 0x38774000,
+0x38778000, 0x3877c000, 0x38780000, 0x38784000, 0x38788000, 0x3878c000,
+0x38790000, 0x38794000, 0x38798000, 0x3879c000, 0x387a0000, 0x387a4000,
+0x387a8000, 0x387ac000, 0x387b0000, 0x387b4000, 0x387b8000, 0x387bc000,
+0x387c0000, 0x387c4000, 0x387c8000, 0x387cc000, 0x387d0000, 0x387d4000,
+0x387d8000, 0x387dc000, 0x387e0000, 0x387e4000, 0x387e8000, 0x387ec000,
+0x387f0000, 0x387f4000, 0x387f8000, 0x387fc000, 0x38000000, 0x38002000,
+0x38004000, 0x38006000, 0x38008000, 0x3800a000, 0x3800c000, 0x3800e000,
+0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801a000,
+0x3801c000, 0x3801e000, 0x38020000, 0x38022000, 0x38024000, 0x38026000,
+0x38028000, 0x3802a000, 0x3802c000, 0x3802e000, 0x38030000, 0x38032000,
+0x38034000, 0x38036000, 0x38038000, 0x3803a000, 0x3803c000, 0x3803e000,
+0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804a000,
+0x3804c000, 0x3804e000, 0x38050000, 0x38052000, 0x38054000, 0x38056000,
+0x38058000, 0x3805a000, 0x3805c000, 0x3805e000, 0x38060000, 0x38062000,
+0x38064000, 0x38066000, 0x38068000, 0x3806a000, 0x3806c000, 0x3806e000,
+0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807a000,
+0x3807c000, 0x3807e000, 0x38080000, 0x38082000, 0x38084000, 0x38086000,
+0x38088000, 0x3808a000, 0x3808c000, 0x3808e000, 0x38090000, 0x38092000,
+0x38094000, 0x38096000, 0x38098000, 0x3809a000, 0x3809c000, 0x3809e000,
+0x380a0000, 0x380a2000, 0x380a4000, 0x380a6000, 0x380a8000, 0x380aa000,
+0x380ac000, 0x380ae000, 0x380b0000, 0x380b2000, 0x380b4000, 0x380b6000,
+0x380b8000, 0x380ba000, 0x380bc000, 0x380be000, 0x380c0000, 0x380c2000,
+0x380c4000, 0x380c6000, 0x380c8000, 0x380ca000, 0x380cc000, 0x380ce000,
+0x380d0000, 0x380d2000, 0x380d4000, 0x380d6000, 0x380d8000, 0x380da000,
+0x380dc000, 0x380de000, 0x380e0000, 0x380e2000, 0x380e4000, 0x380e6000,
+0x380e8000, 0x380ea000, 0x380ec000, 0x380ee000, 0x380f0000, 0x380f2000,
+0x380f4000, 0x380f6000, 0x380f8000, 0x380fa000, 0x380fc000, 0x380fe000,
+0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810a000,
+0x3810c000, 0x3810e000, 0x38110000, 0x38112000, 0x38114000, 0x38116000,
+0x38118000, 0x3811a000, 0x3811c000, 0x3811e000, 0x38120000, 0x38122000,
+0x38124000, 0x38126000, 0x38128000, 0x3812a000, 0x3812c000, 0x3812e000,
+0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813a000,
+0x3813c000, 0x3813e000, 0x38140000, 0x38142000, 0x38144000, 0x38146000,
+0x38148000, 0x3814a000, 0x3814c000, 0x3814e000, 0x38150000, 0x38152000,
+0x38154000, 0x38156000, 0x38158000, 0x3815a000, 0x3815c000, 0x3815e000,
+0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816a000,
+0x3816c000, 0x3816e000, 0x38170000, 0x38172000, 0x38174000, 0x38176000,
+0x38178000, 0x3817a000, 0x3817c000, 0x3817e000, 0x38180000, 0x38182000,
+0x38184000, 0x38186000, 0x38188000, 0x3818a000, 0x3818c000, 0x3818e000,
+0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819a000,
+0x3819c000, 0x3819e000, 0x381a0000, 0x381a2000, 0x381a4000, 0x381a6000,
+0x381a8000, 0x381aa000, 0x381ac000, 0x381ae000, 0x381b0000, 0x381b2000,
+0x381b4000, 0x381b6000, 0x381b8000, 0x381ba000, 0x381bc000, 0x381be000,
+0x381c0000, 0x381c2000, 0x381c4000, 0x381c6000, 0x381c8000, 0x381ca000,
+0x381cc000, 0x381ce000, 0x381d0000, 0x381d2000, 0x381d4000, 0x381d6000,
+0x381d8000, 0x381da000, 0x381dc000, 0x381de000, 0x381e0000, 0x381e2000,
+0x381e4000, 0x381e6000, 0x381e8000, 0x381ea000, 0x381ec000, 0x381ee000,
+0x381f0000, 0x381f2000, 0x381f4000, 0x381f6000, 0x381f8000, 0x381fa000,
+0x381fc000, 0x381fe000, 0x38200000, 0x38202000, 0x38204000, 0x38206000,
+0x38208000, 0x3820a000, 0x3820c000, 0x3820e000, 0x38210000, 0x38212000,
+0x38214000, 0x38216000, 0x38218000, 0x3821a000, 0x3821c000, 0x3821e000,
+0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822a000,
+0x3822c000, 0x3822e000, 0x38230000, 0x38232000, 0x38234000, 0x38236000,
+0x38238000, 0x3823a000, 0x3823c000, 0x3823e000, 0x38240000, 0x38242000,
+0x38244000, 0x38246000, 0x38248000, 0x3824a000, 0x3824c000, 0x3824e000,
+0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825a000,
+0x3825c000, 0x3825e000, 0x38260000, 0x38262000, 0x38264000, 0x38266000,
+0x38268000, 0x3826a000, 0x3826c000, 0x3826e000, 0x38270000, 0x38272000,
+0x38274000, 0x38276000, 0x38278000, 0x3827a000, 0x3827c000, 0x3827e000,
+0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828a000,
+0x3828c000, 0x3828e000, 0x38290000, 0x38292000, 0x38294000, 0x38296000,
+0x38298000, 0x3829a000, 0x3829c000, 0x3829e000, 0x382a0000, 0x382a2000,
+0x382a4000, 0x382a6000, 0x382a8000, 0x382aa000, 0x382ac000, 0x382ae000,
+0x382b0000, 0x382b2000, 0x382b4000, 0x382b6000, 0x382b8000, 0x382ba000,
+0x382bc000, 0x382be000, 0x382c0000, 0x382c2000, 0x382c4000, 0x382c6000,
+0x382c8000, 0x382ca000, 0x382cc000, 0x382ce000, 0x382d0000, 0x382d2000,
+0x382d4000, 0x382d6000, 0x382d8000, 0x382da000, 0x382dc000, 0x382de000,
+0x382e0000, 0x382e2000, 0x382e4000, 0x382e6000, 0x382e8000, 0x382ea000,
+0x382ec000, 0x382ee000, 0x382f0000, 0x382f2000, 0x382f4000, 0x382f6000,
+0x382f8000, 0x382fa000, 0x382fc000, 0x382fe000, 0x38300000, 0x38302000,
+0x38304000, 0x38306000, 0x38308000, 0x3830a000, 0x3830c000, 0x3830e000,
+0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831a000,
+0x3831c000, 0x3831e000, 0x38320000, 0x38322000, 0x38324000, 0x38326000,
+0x38328000, 0x3832a000, 0x3832c000, 0x3832e000, 0x38330000, 0x38332000,
+0x38334000, 0x38336000, 0x38338000, 0x3833a000, 0x3833c000, 0x3833e000,
+0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834a000,
+0x3834c000, 0x3834e000, 0x38350000, 0x38352000, 0x38354000, 0x38356000,
+0x38358000, 0x3835a000, 0x3835c000, 0x3835e000, 0x38360000, 0x38362000,
+0x38364000, 0x38366000, 0x38368000, 0x3836a000, 0x3836c000, 0x3836e000,
+0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837a000,
+0x3837c000, 0x3837e000, 0x38380000, 0x38382000, 0x38384000, 0x38386000,
+0x38388000, 0x3838a000, 0x3838c000, 0x3838e000, 0x38390000, 0x38392000,
+0x38394000, 0x38396000, 0x38398000, 0x3839a000, 0x3839c000, 0x3839e000,
+0x383a0000, 0x383a2000, 0x383a4000, 0x383a6000, 0x383a8000, 0x383aa000,
+0x383ac000, 0x383ae000, 0x383b0000, 0x383b2000, 0x383b4000, 0x383b6000,
+0x383b8000, 0x383ba000, 0x383bc000, 0x383be000, 0x383c0000, 0x383c2000,
+0x383c4000, 0x383c6000, 0x383c8000, 0x383ca000, 0x383cc000, 0x383ce000,
+0x383d0000, 0x383d2000, 0x383d4000, 0x383d6000, 0x383d8000, 0x383da000,
+0x383dc000, 0x383de000, 0x383e0000, 0x383e2000, 0x383e4000, 0x383e6000,
+0x383e8000, 0x383ea000, 0x383ec000, 0x383ee000, 0x383f0000, 0x383f2000,
+0x383f4000, 0x383f6000, 0x383f8000, 0x383fa000, 0x383fc000, 0x383fe000,
+0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840a000,
+0x3840c000, 0x3840e000, 0x38410000, 0x38412000, 0x38414000, 0x38416000,
+0x38418000, 0x3841a000, 0x3841c000, 0x3841e000, 0x38420000, 0x38422000,
+0x38424000, 0x38426000, 0x38428000, 0x3842a000, 0x3842c000, 0x3842e000,
+0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843a000,
+0x3843c000, 0x3843e000, 0x38440000, 0x38442000, 0x38444000, 0x38446000,
+0x38448000, 0x3844a000, 0x3844c000, 0x3844e000, 0x38450000, 0x38452000,
+0x38454000, 0x38456000, 0x38458000, 0x3845a000, 0x3845c000, 0x3845e000,
+0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846a000,
+0x3846c000, 0x3846e000, 0x38470000, 0x38472000, 0x38474000, 0x38476000,
+0x38478000, 0x3847a000, 0x3847c000, 0x3847e000, 0x38480000, 0x38482000,
+0x38484000, 0x38486000, 0x38488000, 0x3848a000, 0x3848c000, 0x3848e000,
+0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849a000,
+0x3849c000, 0x3849e000, 0x384a0000, 0x384a2000, 0x384a4000, 0x384a6000,
+0x384a8000, 0x384aa000, 0x384ac000, 0x384ae000, 0x384b0000, 0x384b2000,
+0x384b4000, 0x384b6000, 0x384b8000, 0x384ba000, 0x384bc000, 0x384be000,
+0x384c0000, 0x384c2000, 0x384c4000, 0x384c6000, 0x384c8000, 0x384ca000,
+0x384cc000, 0x384ce000, 0x384d0000, 0x384d2000, 0x384d4000, 0x384d6000,
+0x384d8000, 0x384da000, 0x384dc000, 0x384de000, 0x384e0000, 0x384e2000,
+0x384e4000, 0x384e6000, 0x384e8000, 0x384ea000, 0x384ec000, 0x384ee000,
+0x384f0000, 0x384f2000, 0x384f4000, 0x384f6000, 0x384f8000, 0x384fa000,
+0x384fc000, 0x384fe000, 0x38500000, 0x38502000, 0x38504000, 0x38506000,
+0x38508000, 0x3850a000, 0x3850c000, 0x3850e000, 0x38510000, 0x38512000,
+0x38514000, 0x38516000, 0x38518000, 0x3851a000, 0x3851c000, 0x3851e000,
+0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852a000,
+0x3852c000, 0x3852e000, 0x38530000, 0x38532000, 0x38534000, 0x38536000,
+0x38538000, 0x3853a000, 0x3853c000, 0x3853e000, 0x38540000, 0x38542000,
+0x38544000, 0x38546000, 0x38548000, 0x3854a000, 0x3854c000, 0x3854e000,
+0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855a000,
+0x3855c000, 0x3855e000, 0x38560000, 0x38562000, 0x38564000, 0x38566000,
+0x38568000, 0x3856a000, 0x3856c000, 0x3856e000, 0x38570000, 0x38572000,
+0x38574000, 0x38576000, 0x38578000, 0x3857a000, 0x3857c000, 0x3857e000,
+0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858a000,
+0x3858c000, 0x3858e000, 0x38590000, 0x38592000, 0x38594000, 0x38596000,
+0x38598000, 0x3859a000, 0x3859c000, 0x3859e000, 0x385a0000, 0x385a2000,
+0x385a4000, 0x385a6000, 0x385a8000, 0x385aa000, 0x385ac000, 0x385ae000,
+0x385b0000, 0x385b2000, 0x385b4000, 0x385b6000, 0x385b8000, 0x385ba000,
+0x385bc000, 0x385be000, 0x385c0000, 0x385c2000, 0x385c4000, 0x385c6000,
+0x385c8000, 0x385ca000, 0x385cc000, 0x385ce000, 0x385d0000, 0x385d2000,
+0x385d4000, 0x385d6000, 0x385d8000, 0x385da000, 0x385dc000, 0x385de000,
+0x385e0000, 0x385e2000, 0x385e4000, 0x385e6000, 0x385e8000, 0x385ea000,
+0x385ec000, 0x385ee000, 0x385f0000, 0x385f2000, 0x385f4000, 0x385f6000,
+0x385f8000, 0x385fa000, 0x385fc000, 0x385fe000, 0x38600000, 0x38602000,
+0x38604000, 0x38606000, 0x38608000, 0x3860a000, 0x3860c000, 0x3860e000,
+0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861a000,
+0x3861c000, 0x3861e000, 0x38620000, 0x38622000, 0x38624000, 0x38626000,
+0x38628000, 0x3862a000, 0x3862c000, 0x3862e000, 0x38630000, 0x38632000,
+0x38634000, 0x38636000, 0x38638000, 0x3863a000, 0x3863c000, 0x3863e000,
+0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864a000,
+0x3864c000, 0x3864e000, 0x38650000, 0x38652000, 0x38654000, 0x38656000,
+0x38658000, 0x3865a000, 0x3865c000, 0x3865e000, 0x38660000, 0x38662000,
+0x38664000, 0x38666000, 0x38668000, 0x3866a000, 0x3866c000, 0x3866e000,
+0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867a000,
+0x3867c000, 0x3867e000, 0x38680000, 0x38682000, 0x38684000, 0x38686000,
+0x38688000, 0x3868a000, 0x3868c000, 0x3868e000, 0x38690000, 0x38692000,
+0x38694000, 0x38696000, 0x38698000, 0x3869a000, 0x3869c000, 0x3869e000,
+0x386a0000, 0x386a2000, 0x386a4000, 0x386a6000, 0x386a8000, 0x386aa000,
+0x386ac000, 0x386ae000, 0x386b0000, 0x386b2000, 0x386b4000, 0x386b6000,
+0x386b8000, 0x386ba000, 0x386bc000, 0x386be000, 0x386c0000, 0x386c2000,
+0x386c4000, 0x386c6000, 0x386c8000, 0x386ca000, 0x386cc000, 0x386ce000,
+0x386d0000, 0x386d2000, 0x386d4000, 0x386d6000, 0x386d8000, 0x386da000,
+0x386dc000, 0x386de000, 0x386e0000, 0x386e2000, 0x386e4000, 0x386e6000,
+0x386e8000, 0x386ea000, 0x386ec000, 0x386ee000, 0x386f0000, 0x386f2000,
+0x386f4000, 0x386f6000, 0x386f8000, 0x386fa000, 0x386fc000, 0x386fe000,
+0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870a000,
+0x3870c000, 0x3870e000, 0x38710000, 0x38712000, 0x38714000, 0x38716000,
+0x38718000, 0x3871a000, 0x3871c000, 0x3871e000, 0x38720000, 0x38722000,
+0x38724000, 0x38726000, 0x38728000, 0x3872a000, 0x3872c000, 0x3872e000,
+0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873a000,
+0x3873c000, 0x3873e000, 0x38740000, 0x38742000, 0x38744000, 0x38746000,
+0x38748000, 0x3874a000, 0x3874c000, 0x3874e000, 0x38750000, 0x38752000,
+0x38754000, 0x38756000, 0x38758000, 0x3875a000, 0x3875c000, 0x3875e000,
+0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876a000,
+0x3876c000, 0x3876e000, 0x38770000, 0x38772000, 0x38774000, 0x38776000,
+0x38778000, 0x3877a000, 0x3877c000, 0x3877e000, 0x38780000, 0x38782000,
+0x38784000, 0x38786000, 0x38788000, 0x3878a000, 0x3878c000, 0x3878e000,
+0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879a000,
+0x3879c000, 0x3879e000, 0x387a0000, 0x387a2000, 0x387a4000, 0x387a6000,
+0x387a8000, 0x387aa000, 0x387ac000, 0x387ae000, 0x387b0000, 0x387b2000,
+0x387b4000, 0x387b6000, 0x387b8000, 0x387ba000, 0x387bc000, 0x387be000,
+0x387c0000, 0x387c2000, 0x387c4000, 0x387c6000, 0x387c8000, 0x387ca000,
+0x387cc000, 0x387ce000, 0x387d0000, 0x387d2000, 0x387d4000, 0x387d6000,
+0x387d8000, 0x387da000, 0x387dc000, 0x387de000, 0x387e0000, 0x387e2000,
+0x387e4000, 0x387e6000, 0x387e8000, 0x387ea000, 0x387ec000, 0x387ee000,
+0x387f0000, 0x387f2000, 0x387f4000, 0x387f6000, 0x387f8000, 0x387fa000,
+0x387fc000, 0x387fe000
+};
+
+static cmsUInt16Number Offset[64] = {
+0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0000, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
+0x0400, 0x0400, 0x0400, 0x0400
+};
+
+static cmsUInt32Number Exponent[64] = {
+0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000,
+0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000,
+0x06000000, 0x06800000, 0x07000000, 0x07800000, 0x08000000, 0x08800000,
+0x09000000, 0x09800000, 0x0a000000, 0x0a800000, 0x0b000000, 0x0b800000,
+0x0c000000, 0x0c800000, 0x0d000000, 0x0d800000, 0x0e000000, 0x0e800000,
+0x0f000000, 0x47800000, 0x80000000, 0x80800000, 0x81000000, 0x81800000,
+0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000,
+0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000,
+0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8a000000, 0x8a800000,
+0x8b000000, 0x8b800000, 0x8c000000, 0x8c800000, 0x8d000000, 0x8d800000,
+0x8e000000, 0x8e800000, 0x8f000000, 0xc7800000
+};
+
+static cmsUInt16Number Base[512] = {
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040,
+0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00,
+0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400,
+0x4800, 0x4c00, 0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00,
+0x7000, 0x7400, 0x7800, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00,
+0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001,
+0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400,
+0x8800, 0x8c00, 0x9000, 0x9400, 0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00,
+0xb000, 0xb400, 0xb800, 0xbc00, 0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400,
+0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00,
+0xfc00, 0xfc00
+};
+
+static cmsUInt8Number  Shift[512] = {
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17,
+0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d,
+0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0d, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13,
+0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x0d
+};
+
+cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h)
+{
+    union {
+        cmsFloat32Number flt;
+        cmsUInt32Number  num;
+    } out;
+
+    int n = h >> 10;
+
+    out.num = Mantissa[  (h & 0x3ff) + Offset[ n ] ] + Exponent[ n ];
+    return out.flt;
+}
+
+cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt)
+{
+    union {
+        cmsFloat32Number flt;
+        cmsUInt32Number  num;
+    } in;
+
+    cmsUInt32Number n, j;
+
+    in.flt = flt;
+    n = in.num;
+    j = (n >> 23) & 0x1ff;
+
+    return (cmsUInt16Number) ((cmsUInt32Number) Base[ j ] + (( n & 0x007fffff) >> Shift[ j ]));
+}
+
+#endif
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c	2013-12-19 12:21:25.963481491 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -55,7 +55,7 @@
 
 #include "lcms2_internal.h"
 
-// This module incorporates several interpolation routines, for 1, 3, 4, 5, 6, 7 and 8 channels on input and
+// This module incorporates several interpolation routines, for 1 to 8 channels on input and
 // up to 65535 channels on output. The user may change those by using the interpolation plug-in
 
 // Interpolation routines by default
@@ -83,7 +83,7 @@
 
 
 // Set the interpolation method
-static
+
 cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
 {
     // Invoke factory, possibly in the Plug-in
@@ -318,6 +318,116 @@
        }
 }
 
+// Bilinear interpolation (16 bits) - cmsFloat32Number version
+static
+void BilinearInterpFloat(const cmsFloat32Number Input[],
+                         cmsFloat32Number Output[],
+                         const cmsInterpParams* p)
+
+{
+#   define LERP(a,l,h)    (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
+#   define DENS(i,j)      (LutTable[(i)+(j)+OutChan])
+
+    const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
+    cmsFloat32Number      px, py;
+    int        x0, y0,
+               X0, Y0, X1, Y1;
+    int        TotalOut, OutChan;
+    cmsFloat32Number      fx, fy,
+        d00, d01, d10, d11,
+        dx0, dx1,
+        dxy;
+
+    TotalOut   = p -> nOutputs;
+    px = Input[0] * p->Domain[0];
+    py = Input[1] * p->Domain[1];
+
+    x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
+    y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
+
+    X0 = p -> opta[1] * x0;
+    X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[1]);
+
+    Y0 = p -> opta[0] * y0;
+    Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[0]);
+
+    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
+
+        d00 = DENS(X0, Y0);
+        d01 = DENS(X0, Y1);
+        d10 = DENS(X1, Y0);
+        d11 = DENS(X1, Y1);
+
+        dx0 = LERP(fx, d00, d10);
+        dx1 = LERP(fx, d01, d11);
+
+        dxy = LERP(fy, dx0, dx1);
+
+        Output[OutChan] = dxy;
+    }
+
+
+#   undef LERP
+#   undef DENS
+}
+
+// Bilinear interpolation (16 bits) - optimized version
+static
+void BilinearInterp16(register const cmsUInt16Number Input[],
+                      register cmsUInt16Number Output[],
+                      register const cmsInterpParams* p)
+
+{
+#define DENS(i,j) (LutTable[(i)+(j)+OutChan])
+#define LERP(a,l,h)     (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
+
+           const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
+           int        OutChan, TotalOut;
+           cmsS15Fixed16Number    fx, fy;
+  register int        rx, ry;
+           int        x0, y0;
+  register int        X0, X1, Y0, Y1;
+           int        d00, d01, d10, d11,
+                      dx0, dx1,
+                      dxy;
+
+    TotalOut   = p -> nOutputs;
+
+    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
+    x0  = FIXED_TO_INT(fx);
+    rx  = FIXED_REST_TO_INT(fx);    // Rest in 0..1.0 domain
+
+
+    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
+    y0  = FIXED_TO_INT(fy);
+    ry  = FIXED_REST_TO_INT(fy);
+
+
+    X0 = p -> opta[1] * x0;
+    X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
+
+    Y0 = p -> opta[0] * y0;
+    Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]);
+
+    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
+
+        d00 = DENS(X0, Y0);
+        d01 = DENS(X0, Y1);
+        d10 = DENS(X1, Y0);
+        d11 = DENS(X1, Y1);
+
+        dx0 = LERP(rx, d00, d10);
+        dx1 = LERP(rx, d01, d11);
+
+        dxy = LERP(ry, dx0, dx1);
+
+        Output[OutChan] = (cmsUInt16Number) dxy;
+    }
+
+
+#   undef LERP
+#   undef DENS
+}
 
 
 // Trilinear interpolation (16 bits) - cmsFloat32Number version
@@ -343,9 +453,21 @@
 
     TotalOut   = p -> nOutputs;
 
-    px = Input[0] * p->Domain[0];
-    py = Input[1] * p->Domain[1];
-    pz = Input[2] * p->Domain[2];
+    // We need some clipping here
+    px = Input[0];
+    py = Input[1];
+    pz = Input[2];
+
+    if (px < 0) px = 0;
+    if (px > 1) px = 1;
+    if (py < 0) py = 0;
+    if (py > 1) py = 1;
+    if (pz < 0) pz = 0;
+    if (pz > 1) pz = 1;
+
+    px *= p->Domain[0];
+    py *= p->Domain[1];
+    pz *= p->Domain[2];
 
     x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
     y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
@@ -486,9 +608,21 @@
 
     TotalOut   = p -> nOutputs;
 
-    px = Input[0] * p->Domain[0];
-    py = Input[1] * p->Domain[1];
-    pz = Input[2] * p->Domain[2];
+    // We need some clipping here
+    px = Input[0];
+    py = Input[1];
+    pz = Input[2];
+
+    if (px < 0) px = 0;
+    if (px > 1) px = 1;
+    if (py < 0) py = 0;
+    if (py > 1) py = 1;
+    if (pz < 0) pz = 0;
+    if (pz > 1) pz = 1;
+
+    px *= p->Domain[0];
+    py *= p->Domain[1];
+    pz *= p->Domain[2];
 
     x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0);
     y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0);
@@ -570,7 +704,6 @@
 
 
 
-#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
 
 static
 void TetrahedralInterp16(register const cmsUInt16Number Input[],
@@ -578,99 +711,131 @@
                          register const cmsInterpParams* p)
 {
     const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
-    cmsS15Fixed16Number    fx, fy, fz;
-    cmsS15Fixed16Number    rx, ry, rz;
-    int                    x0, y0, z0;
-    cmsS15Fixed16Number    c0, c1, c2, c3, Rest;
-    cmsUInt32Number        OutChan;
-    cmsS15Fixed16Number    X0, X1, Y0, Y1, Z0, Z1;
-    cmsUInt32Number        TotalOut = p -> nOutputs;
-
+    cmsS15Fixed16Number fx, fy, fz;
+    cmsS15Fixed16Number rx, ry, rz;
+    int x0, y0, z0;
+    cmsS15Fixed16Number c0, c1, c2, c3, Rest;
+    cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+    cmsUInt32Number TotalOut = p -> nOutputs;
 
-    fx  = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
-    fy  = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
-    fz  = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
+    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
+    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
+    fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
 
-    x0  = FIXED_TO_INT(fx);
-    y0  = FIXED_TO_INT(fy);
-    z0  = FIXED_TO_INT(fz);
+    x0 = FIXED_TO_INT(fx);
+    y0 = FIXED_TO_INT(fy);
+    z0 = FIXED_TO_INT(fz);
 
-    rx  = FIXED_REST_TO_INT(fx);
-    ry  = FIXED_REST_TO_INT(fy);
-    rz  = FIXED_REST_TO_INT(fz);
+    rx = FIXED_REST_TO_INT(fx);
+    ry = FIXED_REST_TO_INT(fy);
+    rz = FIXED_REST_TO_INT(fz);
 
     X0 = p -> opta[2] * x0;
-    X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
+    X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
 
     Y0 = p -> opta[1] * y0;
-    Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
+    Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
 
     Z0 = p -> opta[0] * z0;
-    Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
+    Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
 
-    // These are the 6 Tetrahedral
-    for (OutChan=0; OutChan < TotalOut; OutChan++) {
-
-        c0 = DENS(X0, Y0, Z0);
-
-        if (rx >= ry && ry >= rz) {
-
-            c1 = DENS(X1, Y0, Z0) - c0;
-            c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
-            c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+    LutTable = &LutTable[X0+Y0+Z0];
 
+    // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))
+    // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16
+    // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16
+    // at the cost of being off by one at 7fff and 17ffe.
+
+    if (rx >= ry) {
+        if (ry >= rz) {
+            Y1 += X1;
+            Z1 += Y1;
+            for (; TotalOut; TotalOut--) {
+                c1 = LutTable[X1];
+                c2 = LutTable[Y1];
+                c3 = LutTable[Z1];
+                c0 = *LutTable++;
+                c3 -= c2;
+                c2 -= c1;
+                c1 -= c0;
+                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
+            }
+        } else if (rz >= rx) {
+            X1 += Z1;
+            Y1 += X1;
+            for (; TotalOut; TotalOut--) {
+                c1 = LutTable[X1];
+                c2 = LutTable[Y1];
+                c3 = LutTable[Z1];
+                c0 = *LutTable++;
+                c2 -= c1;
+                c1 -= c3;
+                c3 -= c0;
+                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
+            }
+        } else {
+            Z1 += X1;
+            Y1 += Z1;
+            for (; TotalOut; TotalOut--) {
+                c1 = LutTable[X1];
+                c2 = LutTable[Y1];
+                c3 = LutTable[Z1];
+                c0 = *LutTable++;
+                c2 -= c3;
+                c3 -= c1;
+                c1 -= c0;
+                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
+            }
         }
-        else
-            if (rx >= rz && rz >= ry) {
-
-                c1 = DENS(X1, Y0, Z0) - c0;
-                c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
-                c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
-
+    } else {
+        if (rx >= rz) {
+            X1 += Y1;
+            Z1 += X1;
+            for (; TotalOut; TotalOut--) {
+                c1 = LutTable[X1];
+                c2 = LutTable[Y1];
+                c3 = LutTable[Z1];
+                c0 = *LutTable++;
+                c3 -= c1;
+                c1 -= c2;
+                c2 -= c0;
+                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
             }
-            else
-                if (rz >= rx && rx >= ry) {
-
-                    c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
-                    c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
-                    c3 = DENS(X0, Y0, Z1) - c0;
-
-                }
-                else
-                    if (ry >= rx && rx >= rz) {
-
-                        c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
-                        c2 = DENS(X0, Y1, Z0) - c0;
-                        c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
-
-                    }
-                    else
-                        if (ry >= rz && rz >= rx) {
-
-                            c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
-                            c2 = DENS(X0, Y1, Z0) - c0;
-                            c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
-
-                        }
-                        else
-                            if (rz >= ry && ry >= rx) {
-
-                                c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
-                                c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
-                                c3 = DENS(X0, Y0, Z1) - c0;
-
-                            }
-                            else  {
-                                c1 = c2 = c3 = 0;
-                            }
-
-                            Rest = c1 * rx + c2 * ry + c3 * rz;
-
-                            Output[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
+        } else if (ry >= rz) {
+            Z1 += Y1;
+            X1 += Z1;
+            for (; TotalOut; TotalOut--) {
+                c1 = LutTable[X1];
+                c2 = LutTable[Y1];
+                c3 = LutTable[Z1];
+                c0 = *LutTable++;
+                c1 -= c3;
+                c3 -= c2;
+                c2 -= c0;
+                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
+            }
+        } else {
+            Y1 += Z1;
+            X1 += Y1;
+            for (; TotalOut; TotalOut--) {
+                c1 = LutTable[X1];
+                c2 = LutTable[Y1];
+                c3 = LutTable[Z1];
+                c0 = *LutTable++;
+                c1 -= c2;
+                c2 -= c3;
+                c3 -= c0;
+                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
+            }
+        }
     }
-
 }
-#undef DENS
 
 
 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
@@ -1102,7 +1267,7 @@
        K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
 
        p1 = *p16;
-       memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
+       memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));
 
        T = LutTable + K0;
        p1.Table = T;
@@ -1285,6 +1450,12 @@
                }
                break;
 
+           case 2: // Duotone
+               if (IsFloat)
+                      Interpolation.LerpFloat =  BilinearInterpFloat;
+               else
+                      Interpolation.Lerp16    =  BilinearInterp16;
+               break;
 
            case 3:  // RGB et al
 
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c	2013-12-19 12:21:25.963481491 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -142,6 +142,7 @@
     iohandler ->ContextID = ContextID;
     iohandler ->stream  = (void*) fm;
     iohandler ->UsedSpace = 0;
+    iohandler ->ReportedSize = 0;
     iohandler ->PhysicalFile[0] = 0;
 
     iohandler ->Read    = NULLRead;
@@ -232,13 +233,11 @@
 
     memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
     ResData ->Pointer += size;
+    iohandler->UsedSpace += size;
 
     if (ResData ->Pointer > iohandler->UsedSpace)
         iohandler->UsedSpace = ResData ->Pointer;
 
-
-    iohandler->UsedSpace += size;
-
     return TRUE;
 }
 
@@ -297,6 +296,7 @@
         fm ->FreeBlockOnClose = TRUE;
         fm ->Size    = size;
         fm ->Pointer = 0;
+        iohandler -> ReportedSize = size;
         break;
 
     case 'w':
@@ -307,10 +307,11 @@
         fm ->FreeBlockOnClose = FALSE;
         fm ->Size    = size;
         fm ->Pointer = 0;
+        iohandler -> ReportedSize = 0;
         break;
 
     default:
-        cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow access mode '%c'", *AccessMode);
+        cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown access mode '%c'", *AccessMode);
         return NULL;
     }
 
@@ -407,6 +408,7 @@
              cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
             return NULL;
         }
+        iohandler -> ReportedSize = cmsfilelength(fm);
         break;
 
     case 'w':
@@ -416,11 +418,12 @@
              cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
             return NULL;
         }
+        iohandler -> ReportedSize = 0;
         break;
 
     default:
         _cmsFree(ContextID, iohandler);
-         cmsSignalError(ContextID, cmsERROR_FILE, "Unknow access mode '%c'", *AccessMode);
+         cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode);
         return NULL;
     }
 
@@ -455,6 +458,7 @@
     iohandler -> ContextID = ContextID;
     iohandler -> stream = (void*) Stream;
     iohandler -> UsedSpace = 0;
+    iohandler -> ReportedSize = cmsfilelength(Stream);
     iohandler -> PhysicalFile[0] = 0;
 
     iohandler ->Read    = FileRead;
@@ -643,12 +647,17 @@
     Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
     Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
     Icc -> model           = _cmsAdjustEndianess32(Header.model);
-    _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes);
+    _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes);
     Icc -> Version         = _cmsAdjustEndianess32(Header.version);
 
     // Get size as reported in header
     HeaderSize = _cmsAdjustEndianess32(Header.size);
 
+    // Make sure HeaderSize is lower than profile size
+    if (HeaderSize >= Icc ->IOhandler ->ReportedSize)
+            HeaderSize = Icc ->IOhandler ->ReportedSize;
+
+
     // Get creation date/time
     _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created);
 
@@ -664,6 +673,7 @@
         return FALSE;
     }
 
+
     // Read tag directory
     Icc -> TagCount = 0;
     for (i=0; i < TagCount; i++) {
@@ -673,7 +683,8 @@
         if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE;
 
         // Perform some sanity check. Offset + size should fall inside file.
-        if (Tag.offset + Tag.size > HeaderSize)
+        if (Tag.offset + Tag.size > HeaderSize ||
+            Tag.offset + Tag.size < Tag.offset)
                   continue;
 
         Icc -> TagNames[Icc ->TagCount]   = Tag.sig;
@@ -728,7 +739,7 @@
     Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
     Header.model        = _cmsAdjustEndianess32(Icc -> model);
 
-    _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes);
+    _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes);
 
     // Rendering intent in the header (for embedded profiles)
     Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
@@ -822,7 +833,7 @@
 void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model)
 {
     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
-    Icc -> manufacturer = (cmsUInt32Number) model;
+    Icc -> model = (cmsUInt32Number) model;
 }
 
 
@@ -1138,10 +1149,12 @@
                 continue;
             }
 
-            TypeBase    = TypeHandler ->Signature;
+            TypeBase = TypeHandler ->Signature;
             if (!_cmsWriteTypeBase(io, TypeBase))
                 return FALSE;
 
+            TypeHandler ->ContextID  = Icc ->ContextID;
+            TypeHandler ->ICCVersion = Icc ->Version;
             if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) {
 
                 char String[5];
@@ -1317,8 +1330,12 @@
 
             cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
 
-            if (TypeHandler != NULL)
+            if (TypeHandler != NULL) {
+
+                TypeHandler ->ContextID = Icc ->ContextID;              // As an additional parameters
+                TypeHandler ->ICCVersion = Icc ->Version;
                 TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
+            }
             else
                 _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
         }
@@ -1371,7 +1388,6 @@
     if (n < 0) return NULL;                 // Not found, return NULL
 
 
-
     // If the element is already in memory, return the pointer
     if (Icc -> TagPtrs[n]) {
 
@@ -1406,6 +1422,9 @@
 
     // Read the tag
     Icc -> TagTypeHandlers[n] = TypeHandler;
+
+    TypeHandler ->ContextID = Icc ->ContextID;
+    TypeHandler ->ICCVersion = Icc ->Version;
     Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize);
 
     // The tag type is supported, but something wrong happend and we cannot read the tag.
@@ -1463,11 +1482,15 @@
     cmsTagTypeSignature Type;
     int i;
     cmsFloat64Number Version;
+    char TypeString[5], SigString[5];
 
 
     if (data == NULL) {
 
-         cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag");
+         i = _cmsSearchTag(Icc, sig, FALSE);
+         if (i >= 0)
+             Icc ->TagNames[i] = (cmsTagSignature) 0;
+         // Unsupported by now, reserved for future ampliations (delete)
          return FALSE;
     }
 
@@ -1482,7 +1505,13 @@
             }
             else {
                 TypeHandler = Icc ->TagTypeHandlers[i];
-                TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
+
+                if (TypeHandler != NULL) {
+
+                    TypeHandler ->ContextID = Icc ->ContextID;              // As an additional parameter
+                    TypeHandler ->ICCVersion = Icc ->Version;
+                    TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
+                }
             }
         }
     }
@@ -1514,6 +1543,7 @@
 
     // Now we need to know which type to use. It depends on the version.
     Version = cmsGetProfileVersion(hProfile);
+
     if (TagDescriptor ->DecideType != NULL) {
 
         // Let the tag descriptor to decide the type base on depending on
@@ -1525,33 +1555,47 @@
     }
     else {
 
+
         Type = TagDescriptor ->SupportedTypes[0];
     }
 
     // Does the tag support this type?
     if (!IsTypeSupported(TagDescriptor, Type)) {
-        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig);
+
+        _cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
+        _cmsTagSignature2String(SigString,  sig);
+
+        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
         return FALSE;
     }
 
     // Does we have a handler for this type?
     TypeHandler =  _cmsGetTagTypeHandler(Type);
     if (TypeHandler == NULL) {
-        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig);
+
+        _cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
+        _cmsTagSignature2String(SigString,  sig);
+
+        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
         return FALSE;           // Should never happen
     }
 
+
     // Fill fields on icc structure
     Icc ->TagTypeHandlers[i]  = TypeHandler;
     Icc ->TagNames[i]         = sig;
     Icc ->TagSizes[i]         = 0;
     Icc ->TagOffsets[i]       = 0;
-    Icc ->TagPtrs[i]          = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
+
+    TypeHandler ->ContextID  = Icc ->ContextID;
+    TypeHandler ->ICCVersion = Icc ->Version;
+    Icc ->TagPtrs[i]         = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
 
     if (Icc ->TagPtrs[i] == NULL)  {
 
-        TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
-        cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%x' for tag '%x'", Type, sig);
+        _cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
+        _cmsTagSignature2String(SigString,  sig);
+        cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString);
 
         return FALSE;
     }
@@ -1627,16 +1671,26 @@
     if (data == NULL) {
         MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile));
     } else{
-          MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
+      MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
     }
     if (MemIO == NULL) return 0;
 
     // Obtain type handling for the tag
     TypeHandler = Icc ->TagTypeHandlers[i];
     TagDescriptor = _cmsGetTagDescriptor(sig);
+    if (TagDescriptor == NULL) {
+         cmsCloseIOhandler(MemIO);
+         return 0;
+    }
 
     // Serialize
-    if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0;
+    TypeHandler ->ContextID  = Icc ->ContextID;
+    TypeHandler ->ICCVersion = Icc ->Version;
+
+    if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) {
+        cmsCloseIOhandler(MemIO);
+        return 0;
+    }
 
     // Get Size and close
     rc = MemIO ->Tell(MemIO);
@@ -1687,3 +1741,17 @@
 
     return TRUE;
 }
+
+
+// Returns the tag linked to sig, in the case two tags are sharing same resource
+cmsTagSignature  CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig)
+{
+    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+    int i;
+
+    // Search for given tag in ICC profile directory
+    i = _cmsSearchTag(Icc, sig, FALSE);
+    if (i < 0) return (cmsTagSignature) 0;                 // Not found, return 0
+
+    return Icc -> TagLinked[i];
+}
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c	2013-12-19 12:21:25.967481551 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c	2013-12-19 12:23:00.740901153 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -150,7 +150,7 @@
                 return TRUE;
             }
 
-            return _cmsAdaptationMatrix(Dest, NULL, cmsD50_XYZ(), White);
+            return _cmsAdaptationMatrix(Dest, NULL, White, cmsD50_XYZ());
         }
     }
 
@@ -261,11 +261,81 @@
 
         cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes));
         cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL));
+
+        // Note that it is certainly possible a single profile would have a LUT based
+        // tag for output working in lab and a matrix-shaper for the fallback cases.
+        // This is not allowed by the spec, but this code is tolerant to those cases
+        if (cmsGetPCS(hProfile) == cmsSigLabData) {
+
+             cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
+        }
+
     }
 
     return Lut;
 }
 
+
+
+// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded
+/*static
+cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
+{
+    cmsContext ContextID       = cmsGetProfileContextID(hProfile);
+    cmsPipeline* Lut           = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+    cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile);
+
+    if (Lut == NULL) return NULL;
+
+    // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding,
+    // and since the formatter has already accomodated to 0..1.0, we should undo this change
+    if ( spc == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID));
+    }
+    else
+        if (spc == cmsSigXYZData)
+        {
+            cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID));
+        }
+
+    return Lut;
+}
+*/
+static
+cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
+{
+    cmsContext ContextID       = cmsGetProfileContextID(hProfile);
+    cmsPipeline* Lut           = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+    cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile);
+    cmsColorSpaceSignature PCS = cmsGetPCS(hProfile);
+
+    if (Lut == NULL) return NULL;
+
+    // input and output of transform are in lcms 0..1 encoding.  If XYZ or Lab spaces are used,
+    //  these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0)
+    if ( spc == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID));
+    }
+    else if (spc == cmsSigXYZData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID));
+    }
+
+    if ( PCS == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID));
+    }
+    else if( PCS == cmsSigXYZData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID));
+    }
+
+    return Lut;
+}
+
+
 // Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
 // is adjusted here in order to create a LUT that takes care of all those details
 cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
@@ -275,10 +345,30 @@
     cmsTagSignature tagFloat = Device2PCSFloat[Intent];
     cmsContext ContextID = cmsGetProfileContextID(hProfile);
 
+    // On named color, take the appropiate tag
+    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
+
+        cmsPipeline* Lut;
+        cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag);
+
+        if (nc == NULL) return NULL;
+
+        Lut = cmsPipelineAlloc(ContextID, 0, 0);
+        if (Lut == NULL) {
+            cmsFreeNamedColorList(nc);
+            return NULL;
+        }
+
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE));
+        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
+        return Lut;
+    }
+
     if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence
 
-        // Floating point LUT are always V4, so no adjustment is required
-        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+        // Floating point LUT are always V4, but the encoding range is no
+        // longer 0..1.0, so we need to add an stage depending on the color space
+         return _cmsReadFloatInputTag(hProfile, tagFloat);
     }
 
     // Revert to perceptual if no tag is found
@@ -304,6 +394,10 @@
         if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
             return Lut;
 
+        // If the input is Lab, add also a conversion at the begin
+        if (cmsGetColorSpace(hProfile) == cmsSigLabData)
+            cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
+
         // Add a matrix for conversion V2 to V4 Lab PCS
         cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
         return Lut;
@@ -407,6 +501,14 @@
     Lut = cmsPipelineAlloc(ContextID, 3, 3);
     if (Lut != NULL) {
 
+        // Note that it is certainly possible a single profile would have a LUT based
+        // tag for output working in lab and a matrix-shaper for the fallback cases.
+        // This is not allowed by the spec, but this code is tolerant to those cases
+        if (cmsGetPCS(hProfile) == cmsSigLabData) {
+
+             cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
+        }
+
         cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL));
         cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes));
     }
@@ -415,6 +517,88 @@
     return Lut;
 }
 
+
+// Change CLUT interpolation to trilinear
+static
+void ChangeInterpolationToTrilinear(cmsPipeline* Lut)
+{
+    cmsStage* Stage;
+
+    for (Stage = cmsPipelineGetPtrToFirstStage(Lut);
+        Stage != NULL;
+        Stage = cmsStageNext(Stage)) {
+
+            if (cmsStageType(Stage) == cmsSigCLutElemType) {
+
+                _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data;
+
+                CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR;
+                _cmsSetInterpolationRoutine(CLUT ->Params);
+            }
+    }
+}
+
+
+// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded
+/*static
+cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
+{
+    cmsContext ContextID       = cmsGetProfileContextID(hProfile);
+    cmsPipeline* Lut           = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+    cmsColorSpaceSignature PCS = cmsGetPCS(hProfile);
+
+    if (Lut == NULL) return NULL;
+
+    // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding,
+    // and since the formatter has already accomodated to 0..1.0, we should undo this change
+    if ( PCS == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID));
+    }
+    else
+        if (PCS == cmsSigXYZData)
+        {
+            cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID));
+        }
+
+    return Lut;
+}*/
+
+static
+cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
+{
+    cmsContext ContextID       = cmsGetProfileContextID(hProfile);
+    cmsPipeline* Lut           = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+    cmsColorSpaceSignature PCS = cmsGetPCS(hProfile);
+    cmsColorSpaceSignature dataSpace = cmsGetColorSpace(hProfile);
+
+    if (Lut == NULL) return NULL;
+
+    // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding,
+    // and since the formatter has already accomodated to 0..1.0, we should undo this change
+    if ( PCS == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID));
+    }
+    else
+        if (PCS == cmsSigXYZData)
+        {
+            cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID));
+        }
+
+    // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline
+    if ( dataSpace == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID));
+    }
+    else if ( dataSpace == cmsSigXYZData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID));
+    }
+
+    return Lut;
+}
+
 // Create an output MPE LUT from agiven profile. Version mismatches are handled here
 cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
 {
@@ -425,8 +609,8 @@
 
     if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence
 
-        // Floating point LUT are always V4, so no adjustment is required
-        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+        // Floating point LUT are always V4
+        return _cmsReadFloatOutputTag(hProfile, tagFloat);
     }
 
     // Revert to perceptual if no tag is found
@@ -447,6 +631,12 @@
 
         // The profile owns the Lut, so we need to copy it
         Lut = cmsPipelineDup(Lut);
+        if (Lut == NULL) return NULL;
+
+        // Now it is time for a controversial stuff. I found that for 3D LUTS using
+        // Lab used as indexer space,  trilinear interpolation should be used
+        if (cmsGetPCS(hProfile) == cmsSigLabData)
+                             ChangeInterpolationToTrilinear(Lut);
 
         // We need to adjust data only for Lab and Lut16 type
         if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
@@ -454,6 +644,11 @@
 
         // Add a matrix for conversion V4 to V2 Lab PCS
         cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
+
+        // If the output is Lab, add also a conversion at the end
+        if (cmsGetColorSpace(hProfile) == cmsSigLabData)
+            cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
+
         return Lut;
     }
 
@@ -467,12 +662,46 @@
               return BuildGrayOutputPipeline(hProfile);
     }
 
-    // Not gray, create a normal matrix-shaper
+    // Not gray, create a normal matrix-shaper, which only operates in XYZ space
     return BuildRGBOutputMatrixShaper(hProfile);
 }
 
 // ---------------------------------------------------------------------------------------------------------------
 
+// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded
+static
+cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
+{
+    cmsContext ContextID       = cmsGetProfileContextID(hProfile);
+    cmsPipeline* Lut           = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+    cmsColorSpaceSignature PCS = cmsGetPCS(hProfile);
+    cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile);
+
+    if (Lut == NULL) return NULL;
+
+    if (spc == cmsSigLabData)
+    {
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID));
+    }
+    else
+        if (spc == cmsSigXYZData)
+        {
+            cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID));
+        }
+
+        if (PCS == cmsSigLabData)
+        {
+            cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID));
+        }
+        else
+            if (PCS == cmsSigXYZData)
+            {
+                cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID));
+            }
+
+            return Lut;
+}
+
 // This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
 // tag name here may default to AToB0
 cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
@@ -483,10 +712,30 @@
     cmsTagSignature tagFloat = Device2PCSFloat[Intent];
     cmsContext ContextID = cmsGetProfileContextID(hProfile);
 
+
+    // On named color, take the appropiate tag
+    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
+
+        cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag);
+
+        if (nc == NULL) return NULL;
+
+        Lut = cmsPipelineAlloc(ContextID, 0, 0);
+        if (Lut == NULL) {
+            cmsFreeNamedColorList(nc);
+            return NULL;
+        }
+
+        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE));
+        if (cmsGetColorSpace(hProfile) == cmsSigLabData)
+              cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
+        return Lut;
+    }
+
     if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence
 
-        // Floating point LUT are always V4, no adjustment is required
-        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+        // Floating point LUT are always V
+        return _cmsReadFloatDevicelinkTag(hProfile, tagFloat);
     }
 
     tagFloat = Device2PCSFloat[0];
@@ -509,6 +758,12 @@
 
     // The profile owns the Lut, so we need to copy it
     Lut = cmsPipelineDup(Lut);
+    if (Lut == NULL) return NULL;
+
+     // Now it is time for a controversial stuff. I found that for 3D LUTS using
+     // Lab used as indexer space,  trilinear interpolation should be used
+    if (cmsGetColorSpace(hProfile) == cmsSigLabData)
+                        ChangeInterpolationToTrilinear(Lut);
 
     // After reading it, we have info about the original type
     OriginalType =  _cmsGetTagTrueType(hProfile, tag16);
@@ -558,7 +813,7 @@
 }
 
 // Returns TRUE if the intent is implemented as CLUT
-cmsBool  CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection)
+cmsBool  CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection)
 {
     const cmsTagSignature* TagTable;
 
@@ -589,7 +844,7 @@
 
 // Return info about supported intents
 cmsBool  CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile,
-                                        cmsUInt32Number Intent, int UsedDirection)
+                                        cmsUInt32Number Intent, cmsUInt32Number UsedDirection)
 {
 
     if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE;
@@ -607,7 +862,6 @@
 
 // Read both, profile sequence description and profile sequence id if present. Then combine both to
 // create qa unique structure holding both. Shame on ICC to store things in such complicated way.
-
 cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile)
 {
     cmsSEQ* ProfileSeq;
@@ -632,12 +886,13 @@
     NewSeq = cmsDupProfileSequenceDescription(ProfileSeq);
 
     // Ok, proceed to the mixing
-    for (i=0; i < ProfileSeq ->n; i++) {
+    if (NewSeq != NULL) {
+        for (i=0; i < ProfileSeq ->n; i++) {
 
-        memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID));
-        NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description);
+            memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID));
+            NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description);
+        }
     }
-
     return NewSeq;
 }
 
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c	2013-12-19 12:21:25.967481551 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c	2013-12-19 12:23:00.744901214 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -154,7 +154,7 @@
     for (i=0; i < n; i++) {
 
         // Get asked type
-        Type  = va_arg(args, cmsStageSignature);
+        Type  = (cmsStageSignature)va_arg(args, cmsStageSignature);
         if (mpe ->Type != Type) {
 
             va_end(args);       // Mismatch. We are done.
@@ -197,9 +197,14 @@
                     cmsFloat32Number Out[],
                     const cmsStage *mpe)
 {
-    _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data;
+    _cmsStageToneCurvesData* Data;
     cmsUInt32Number i;
 
+    _cmsAssert(mpe != NULL);
+
+    Data = (_cmsStageToneCurvesData*) mpe ->Data;
+    if (Data == NULL) return;
+
     if (Data ->TheCurves == NULL) return;
 
     for (i=0; i < Data ->nCurves; i++) {
@@ -210,9 +215,14 @@
 static
 void CurveSetElemTypeFree(cmsStage* mpe)
 {
-    _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data;
+    _cmsStageToneCurvesData* Data;
     cmsUInt32Number i;
 
+    _cmsAssert(mpe != NULL);
+
+    Data = (_cmsStageToneCurvesData*) mpe ->Data;
+    if (Data == NULL) return;
+
     if (Data ->TheCurves != NULL) {
         for (i=0; i < Data ->nCurves; i++) {
             if (Data ->TheCurves[i] != NULL)
@@ -275,12 +285,14 @@
                                      EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL );
     if (NewMPE == NULL) return NULL;
 
-    NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData));
+    NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData));
     if (NewElem == NULL) {
         cmsStageFree(NewMPE);
         return NULL;
     }
 
+    NewMPE ->Data  = (void*) NewElem;
+
     NewElem ->nCurves   = nChannels;
     NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*));
     if (NewElem ->TheCurves == NULL) {
@@ -301,11 +313,10 @@
             cmsStageFree(NewMPE);
             return NULL;
         }
-    }
 
-    NewMPE ->Data  = (void*) NewElem;
+    }
 
-    return NewMPE;
+   return NewMPE;
 }
 
 
@@ -402,6 +413,9 @@
     n = Rows * Cols;
 
     // Check for overflow
+    if (n == 0) return NULL;
+    if (n >= UINT_MAX / Cols) return NULL;
+    if (n >= UINT_MAX / Rows) return NULL;
     if (n < Rows || n < Cols) return NULL;
 
     NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows,
@@ -479,10 +493,20 @@
 static
 cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b)
 {
-    cmsUInt32Number rv;
+    cmsUInt32Number rv, dim;
+
+    _cmsAssert(Dims != NULL);
+
+    for (rv = 1; b > 0; b--) {
+
+        dim = Dims[b-1];
+        if (dim == 0) return 0;  // Error
+
+        rv *= dim;
 
-    for (rv = 1; b > 0; b--)
-        rv *= Dims[b-1];
+        // Check for overflow
+        if (rv > UINT_MAX / dim) return 0;
+    }
 
     return rv;
 }
@@ -549,17 +573,35 @@
     _cmsStageCLutData* NewElem;
     cmsStage* NewMPE;
 
+    _cmsAssert(clutPoints != NULL);
+
+    if (inputChan > MAX_INPUT_DIMENSIONS) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS);
+        return NULL;
+    }
+
     NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
                                      EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL );
 
     if (NewMPE == NULL) return NULL;
 
-    NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData));
-    if (NewElem == NULL) return NULL;
+    NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData));
+    if (NewElem == NULL) {
+        cmsStageFree(NewMPE);
+        return NULL;
+    }
+
+    NewMPE ->Data  = (void*) NewElem;
 
     NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan);
     NewElem -> HasFloatValues = FALSE;
 
+    if (n == 0) {
+        cmsStageFree(NewMPE);
+        return NULL;
+    }
+
+
     NewElem ->Tab.T  = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number));
     if (NewElem ->Tab.T == NULL) {
         cmsStageFree(NewMPE);
@@ -578,8 +620,6 @@
         return NULL;
     }
 
-    NewMPE ->Data  = (void*) NewElem;
-
     return NewMPE;
 }
 
@@ -623,18 +663,37 @@
 {
     cmsUInt32Number i, n;
     _cmsStageCLutData* NewElem;
-    cmsStage* NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
-                                             EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL);
+    cmsStage* NewMPE;
 
+    _cmsAssert(clutPoints != NULL);
+
+    if (inputChan > MAX_INPUT_DIMENSIONS) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS);
+        return NULL;
+    }
+
+    NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
+                                             EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL);
     if (NewMPE == NULL) return NULL;
 
 
-    NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData));
-    if (NewElem == NULL) return NULL;
+    NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData));
+    if (NewElem == NULL) {
+        cmsStageFree(NewMPE);
+        return NULL;
+    }
 
-    NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan);
+    NewMPE ->Data  = (void*) NewElem;
+
+    // There is a potential integer overflow on conputing n and nEntries.
+    NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan);
     NewElem -> HasFloatValues = TRUE;
 
+    if (n == 0) {
+        cmsStageFree(NewMPE);
+        return NULL;
+    }
+
     NewElem ->Tab.TFloat  = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number));
     if (NewElem ->Tab.TFloat == NULL) {
         cmsStageFree(NewMPE);
@@ -647,7 +706,6 @@
         }
     }
 
-    NewMPE ->Data  = (void*) NewElem;
 
     NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints,  inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT);
     if (NewElem ->Params == NULL) {
@@ -715,8 +773,13 @@
     int nInputs, nOutputs;
     cmsUInt32Number* nSamples;
     cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS];
-    _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
+    _cmsStageCLutData* clut;
 
+    if (mpe == NULL) return FALSE;
+
+    clut = (_cmsStageCLutData*) mpe->Data;
+
+    if (clut == NULL) return FALSE;
 
     nSamples = clut->Params ->nSamples;
     nInputs  = clut->Params ->nInputs;
@@ -726,6 +789,7 @@
     if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
 
     nTotalPoints = CubeSize(nSamples, nInputs);
+    if (nTotalPoints == 0) return FALSE;
 
     index = 0;
     for (i = 0; i < nTotalPoints; i++) {
@@ -779,6 +843,7 @@
     if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
 
     nTotalPoints = CubeSize(nSamples, nInputs);
+    if (nTotalPoints == 0) return FALSE;
 
     index = 0;
     for (i = 0; i < nTotalPoints; i++) {
@@ -828,6 +893,7 @@
     if (nInputs >= cmsMAXCHANNELS) return FALSE;
 
     nTotalPoints = CubeSize(clutPoints, nInputs);
+    if (nTotalPoints == 0) return FALSE;
 
     for (i = 0; i < nTotalPoints; i++) {
 
@@ -857,6 +923,7 @@
     if (nInputs >= cmsMAXCHANNELS) return FALSE;
 
     nTotalPoints = CubeSize(clutPoints, nInputs);
+    if (nTotalPoints == 0) return FALSE;
 
     for (i = 0; i < nTotalPoints; i++) {
 
@@ -992,6 +1059,89 @@
 }
 
 
+// To Lab to float. Note that the MPE gives numbers in normal Lab range
+// and we need 0..1.0 range for the formatters
+// L* : 0...100 => 0...1.0  (L* / 100)
+// ab* : -128..+127 to 0..1  ((ab* + 128) / 255)
+
+cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID)
+{
+    static const cmsFloat64Number a1[] = {
+        1.0/100.0, 0, 0,
+        0, 1.0/255.0, 0,
+        0, 0, 1.0/255.0
+    };
+
+    static const cmsFloat64Number o1[] = {
+        0,
+        128.0/255.0,
+        128.0/255.0
+    };
+
+    cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1);
+
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigLab2FloatPCS;
+    return mpe;
+}
+
+// Fom XYZ to floating point PCS
+cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID)
+{
+#define n (32768.0/65535.0)
+    static const cmsFloat64Number a1[] = {
+        n, 0, 0,
+        0, n, 0,
+        0, 0, n
+    };
+#undef n
+
+    cmsStage *mpe =  cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL);
+
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigXYZ2FloatPCS;
+    return mpe;
+}
+
+cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID)
+{
+    static const cmsFloat64Number a1[] = {
+        100.0, 0, 0,
+        0, 255.0, 0,
+        0, 0, 255.0
+    };
+
+    static const cmsFloat64Number o1[] = {
+        0,
+        -128.0,
+        -128.0
+    };
+
+    cmsStage *mpe =  cmsStageAllocMatrix(ContextID, 3, 3, a1, o1);
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigFloatPCS2Lab;
+    return mpe;
+}
+
+cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID)
+{
+#define n (65535.0/32768.0)
+
+    static const cmsFloat64Number a1[] = {
+        n, 0, 0,
+        0, n, 0,
+        0, 0, n
+    };
+#undef n
+
+    cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL);
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigFloatPCS2XYZ;
+    return mpe;
+}
+
+
+
 // ********************************************************************************
 // Type cmsSigXYZ2LabElemType
 // ********************************************************************************
@@ -1201,22 +1351,28 @@
        NewLUT ->DupDataFn   = NULL;
        NewLUT ->FreeDataFn  = NULL;
        NewLUT ->Data        = NewLUT;
-
-       NewLUT ->ContextID    = ContextID;
+       NewLUT ->ContextID   = ContextID;
 
        BlessLUT(NewLUT);
 
        return NewLUT;
 }
 
+cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut)
+{
+    _cmsAssert(lut != NULL);
+    return lut ->ContextID;
+}
 
 cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     return lut ->InputChannels;
 }
 
 cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     return lut ->OutputChannels;
 }
 
@@ -1244,6 +1400,7 @@
 // Default to evaluate the LUT on 16 bit-basis.
 void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[],  const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     lut ->Eval16Fn(In, Out, lut->Data);
 }
 
@@ -1251,6 +1408,7 @@
 // Does evaluate the LUT on cmsFloat32Number-basis.
 void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     lut ->EvalFloatFn(In, Out, lut);
 }
 
@@ -1288,8 +1446,10 @@
             Anterior = NewMPE;
     }
 
-    NewLUT ->DupDataFn  = lut ->DupDataFn;
-    NewLUT ->FreeDataFn = lut ->FreeDataFn;
+    NewLUT ->Eval16Fn    = lut ->Eval16Fn;
+    NewLUT ->EvalFloatFn = lut ->EvalFloatFn;
+    NewLUT ->DupDataFn   = lut ->DupDataFn;
+    NewLUT ->FreeDataFn  = lut ->FreeDataFn;
 
     if (NewLUT ->DupDataFn != NULL)
         NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data);
@@ -1306,6 +1466,9 @@
 {
     cmsStage* Anterior = NULL, *pt;
 
+    _cmsAssert(lut != NULL);
+    _cmsAssert(mpe != NULL);
+
     switch (loc) {
 
         case cmsAT_BEGIN:
@@ -1456,13 +1619,13 @@
     return n;
 }
 
-// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional
+// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional
 // duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality.
 void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
                                         _cmsOPTeval16Fn Eval16,
                                         void* PrivateData,
-                                        _cmsOPTfreeDataFn FreePrivateDataFn,
-                                        _cmsOPTdupDataFn DupPrivateDataFn)
+                                        _cmsFreeUserDataFn FreePrivateDataFn,
+                                        _cmsDupUserDataFn  DupPrivateDataFn)
 {
 
     Lut ->Eval16Fn = Eval16;
@@ -1640,3 +1803,4 @@
     return TRUE;
 }
 
+
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c	2013-12-19 12:21:25.967481551 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c	2013-12-19 12:21:25.967481551 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c	2013-12-19 12:23:00.744901214 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -202,3 +202,4 @@
     r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ];
 }
 
+
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c	2013-12-19 12:21:25.971481609 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c	2013-12-19 12:23:00.744901214 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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"),
@@ -117,7 +117,7 @@
 }
 
 
-// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two.
+// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two.
 static
 cmsBool GrowMLUtable(cmsMLU* mlu)
 {
@@ -130,7 +130,7 @@
     AllocatedEntries = mlu ->AllocatedEntries * 2;
 
     // Check for overflow
-    if (AllocatedEntries < mlu ->AllocatedEntries) return FALSE;
+    if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE;
 
     // Reallocate the memory
     NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));
@@ -359,9 +359,9 @@
     if (Best == -1)
         Best = 0;
 
-    v = mlu ->Entries + Best;
+     v = mlu ->Entries + Best;
 
-    if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
+     if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
     if (UsedCountryCode  != NULL) *UsedCountryCode = v ->Country;
 
     if (len != NULL) *len   = v ->Len;
@@ -372,8 +372,8 @@
 
 // Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len
 cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
-                                         const char LanguageCode[3], const char CountryCode[3],
-                                         char* Buffer, cmsUInt32Number BufferSize)
+                                       const char LanguageCode[3], const char CountryCode[3],
+                                       char* Buffer, cmsUInt32Number BufferSize)
 {
     const wchar_t *Wide;
     cmsUInt32Number  StrLen = 0;
@@ -417,8 +417,8 @@
 
 // Obtain a wide representation of the MLU, on depending on current locale settings
 cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
-                                        const char LanguageCode[3], const char CountryCode[3],
-                                        wchar_t* Buffer, cmsUInt32Number BufferSize)
+                                      const char LanguageCode[3], const char CountryCode[3],
+                                      wchar_t* Buffer, cmsUInt32Number BufferSize)
 {
     const wchar_t *Wide;
     cmsUInt32Number  StrLen = 0;
@@ -491,6 +491,9 @@
     else
         size = v ->Allocated * 2;
 
+    // Keep a maximum color lists can grow, 100K entries seems reasonable
+    if (size > 1024*100) return FALSE;
+
     NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));
     if (NewPtr == NULL)
         return FALSE;
@@ -516,6 +519,8 @@
 
     strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix));
     strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix));
+    v->Prefix[32] = v->Suffix[32] = 0;
+
     v -> ColorantCount = ColorantCount;
 
     return v;
@@ -569,9 +574,14 @@
     for (i=0; i < 3; i++)
         NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i];
 
-    if (Name != NULL)
+    if (Name != NULL) {
+
         strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name,
                     sizeof(NamedColorList ->List[NamedColorList ->nColors].Name));
+
+        NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0;
+
+    }
     else
         NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0;
 
@@ -645,6 +655,24 @@
 }
 
 static
+void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
+{
+    cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
+    cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
+
+    if (index >= NamedColorList-> nColors) {
+        cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
+    }
+    else {
+
+            // Named color always uses Lab
+            Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0);
+            Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0);
+            Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0);
+    }
+}
+
+static
 void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
 {
     cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
@@ -662,15 +690,15 @@
 
 
 // Named color lookup element
-cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList)
+cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)
 {
     return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
-                                     cmsSigNamedColorElemType,
-                                     1, 3,
-                                     EvalNamedColor,
-                                     DupNamedColorList,
-                                     FreeNamedColorList,
-                                     cmsDupNamedColorList(NamedColorList));
+                                   cmsSigNamedColorElemType,
+                                   1, UsePCS ? 3 : NamedColorList ->ColorantCount,
+                                   UsePCS ? EvalNamedColorPCS : EvalNamedColor,
+                                   DupNamedColorList,
+                                   FreeNamedColorList,
+                                   cmsDupNamedColorList(NamedColorList));
 
 }
 
@@ -771,3 +799,131 @@
     return NULL;
 }
 
+// Dictionaries --------------------------------------------------------------------------------------------------------
+
+// Dictionaries are just very simple linked lists
+
+
+typedef struct _cmsDICT_struct {
+    cmsDICTentry* head;
+    cmsContext ContextID;
+} _cmsDICT;
+
+
+// Allocate an empty dictionary
+cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID)
+{
+    _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT));
+    if (dict == NULL) return NULL;
+
+    dict ->ContextID = ContextID;
+    return (cmsHANDLE) dict;
+
+}
+
+// Dispose resources
+void CMSEXPORT cmsDictFree(cmsHANDLE hDict)
+{
+    _cmsDICT* dict = (_cmsDICT*) hDict;
+    cmsDICTentry *entry, *next;
+
+    _cmsAssert(dict != NULL);
+
+    // Walk the list freeing all nodes
+    entry = dict ->head;
+    while (entry != NULL) {
+
+            if (entry ->DisplayName  != NULL) cmsMLUfree(entry ->DisplayName);
+            if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue);
+            if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name);
+            if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value);
+
+            // Don't fall in the habitual trap...
+            next = entry ->Next;
+            _cmsFree(dict ->ContextID, entry);
+
+            entry = next;
+    }
+
+    _cmsFree(dict ->ContextID, dict);
+}
+
+
+// Duplicate a wide char string
+static
+wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr)
+{
+    if (ptr == NULL) return NULL;
+    return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t));
+}
+
+// Add a new entry to the linked list
+cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue)
+{
+    _cmsDICT* dict = (_cmsDICT*) hDict;
+    cmsDICTentry *entry;
+
+    _cmsAssert(dict != NULL);
+    _cmsAssert(Name != NULL);
+
+    entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry));
+    if (entry == NULL) return FALSE;
+
+    entry ->DisplayName  = cmsMLUdup(DisplayName);
+    entry ->DisplayValue = cmsMLUdup(DisplayValue);
+    entry ->Name         = DupWcs(dict ->ContextID, Name);
+    entry ->Value        = DupWcs(dict ->ContextID, Value);
+
+    entry ->Next = dict ->head;
+    dict ->head = entry;
+
+    return TRUE;
+}
+
+
+// Duplicates an existing dictionary
+cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict)
+{
+    _cmsDICT* old_dict = (_cmsDICT*) hDict;
+    cmsHANDLE hNew;
+    _cmsDICT* new_dict;
+    cmsDICTentry *entry;
+
+    _cmsAssert(old_dict != NULL);
+
+    hNew  = cmsDictAlloc(old_dict ->ContextID);
+    if (hNew == NULL) return NULL;
+
+    new_dict = (_cmsDICT*) hNew;
+
+    // Walk the list freeing all nodes
+    entry = old_dict ->head;
+    while (entry != NULL) {
+
+        if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) {
+
+            cmsDictFree(hNew);
+            return NULL;
+        }
+
+        entry = entry -> Next;
+    }
+
+    return hNew;
+}
+
+// Get a pointer to the linked list
+const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict)
+{
+    _cmsDICT* dict = (_cmsDICT*) hDict;
+
+    if (dict == NULL) return NULL;
+    return dict ->head;
+}
+
+// Helper For external languages
+const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e)
+{
+     if (e == NULL) return NULL;
+     return e ->Next;
+}
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c	2013-12-19 12:21:25.971481609 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -223,6 +223,12 @@
         // Remove V2 to V4 followed by V4 to V2
         Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2);
 
+        // Remove float pcs Lab conversions
+        Opt |= _Remove2Op(Lut, cmsSigLab2FloatPCS, cmsSigFloatPCS2Lab);
+
+        // Remove float pcs Lab conversions
+        Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ);
+
         if (Opt) AnyOpt = TRUE;
 
     } while (Opt);
@@ -298,7 +304,7 @@
                                int nOutputs, cmsToneCurve** Out )
 {
     int i;
-    Prelin16Data* p16 = (Prelin16Data*) _cmsMallocZero(ContextID, sizeof(Prelin16Data));
+    Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data));
     if (p16 == NULL) return NULL;
 
     p16 ->nInputs = nInputs;
@@ -411,42 +417,54 @@
         return FALSE;
     }
 
-    px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0;
-    py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0;
-    pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0;
-    pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0;
-
-    x0 = (int) floor(px);
-    y0 = (int) floor(py);
-    z0 = (int) floor(pz);
-    w0 = (int) floor(pw);
-
     if (nChannelsIn == 4) {
 
+        px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0;
+        py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0;
+        pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0;
+        pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0;
+
+        x0 = (int) floor(px);
+        y0 = (int) floor(py);
+        z0 = (int) floor(pz);
+        w0 = (int) floor(pw);
+
         if (((px - x0) != 0) ||
             ((py - y0) != 0) ||
             ((pz - z0) != 0) ||
             ((pw - w0) != 0)) return FALSE; // Not on exact node
 
         index = p16 -> opta[3] * x0 +
-            p16 -> opta[2] * y0 +
-            p16 -> opta[1] * z0 +
-            p16 -> opta[0] * w0;
+                p16 -> opta[2] * y0 +
+                p16 -> opta[1] * z0 +
+                p16 -> opta[0] * w0;
     }
     else
         if (nChannelsIn == 3) {
 
+            px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0;
+            py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0;
+            pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0;
+
+            x0 = (int) floor(px);
+            y0 = (int) floor(py);
+            z0 = (int) floor(pz);
+
             if (((px - x0) != 0) ||
                 ((py - y0) != 0) ||
                 ((pz - z0) != 0)) return FALSE;  // Not on exact node
 
             index = p16 -> opta[2] * x0 +
-                p16 -> opta[1] * y0 +
-                p16 -> opta[0] * z0;
+                    p16 -> opta[1] * y0 +
+                    p16 -> opta[0] * z0;
         }
         else
             if (nChannelsIn == 1) {
 
+                px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0;
+
+                x0 = (int) floor(px);
+
                 if (((px - x0) != 0)) return FALSE; // Not on exact node
 
                 index = p16 -> opta[0] * x0;
@@ -462,13 +480,15 @@
             return TRUE;
 }
 
-// Auxiliar, to see if two values are equal.
+// Auxiliar, to see if two values are equal or very different
 static
 cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] )
 {
     int i;
 
     for (i=0; i < n; i++) {
+
+        if (abs(White1[i] - White2[i]) > 0xf000) return TRUE;  // Values are so extremly different that the fixup should be avoided
         if (White1[i] != White2[i]) return FALSE;
     }
     return TRUE;
@@ -491,6 +511,8 @@
         &WhitePointOut, NULL, &nOuts)) return FALSE;
 
     // It needs to be fixed?
+    if (Lut ->InputChannels != nIns) return FALSE;
+    if (Lut ->OutputChannels != nOuts) return FALSE;
 
     cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut);
 
@@ -555,6 +577,7 @@
 {
     cmsPipeline* Src;
     cmsPipeline* Dest;
+    cmsStage* mpe;
     cmsStage* CLUT;
     cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
     int nGridPoints;
@@ -580,6 +603,13 @@
 
     Src = *Lut;
 
+   // Named color pipelines cannot be optimized either
+   for (mpe = cmsPipelineGetPtrToFirstStage(Src);
+         mpe != NULL;
+         mpe = cmsStageNext(mpe)) {
+            if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
+    }
+
     // Allocate an empty LUT
     Dest =  cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
     if (!Dest) return FALSE;
@@ -817,8 +847,8 @@
     cmsUInt8Number         r, g, b;
     cmsS15Fixed16Number    rx, ry, rz;
     cmsS15Fixed16Number    c0, c1, c2, c3, Rest;
-    int        OutChan;
-    register   cmsS15Fixed16Number    X0, X1, Y0, Y1, Z0, Z1;
+    int                    OutChan;
+    register cmsS15Fixed16Number    X0, X1, Y0, Y1, Z0, Z1;
     Prelin8Data* p8 = (Prelin8Data*) D;
     register const cmsInterpParams* p = p8 ->p;
     int                    TotalOut = p -> nOutputs;
@@ -892,15 +922,35 @@
                             }
 
 
-                            Rest = c1 * rx + c2 * ry + c3 * rz;
-
-                            Output[OutChan] = (cmsUInt16Number)c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
+                            Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
+                            Output[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest>>16))>>16);
 
     }
 }
 
 #undef DENS
 
+
+// Curves that contain wide empty areas are not optimizeable
+static
+cmsBool IsDegenerated(const cmsToneCurve* g)
+{
+    int i, Zeros = 0, Poles = 0;
+    int nEntries = g ->nEntries;
+
+    for (i=0; i < nEntries; i++) {
+
+        if (g ->Table16[i] == 0x0000) Zeros++;
+        if (g ->Table16[i] == 0xffff) Poles++;
+    }
+
+    if (Zeros == 1 && Poles == 1) return FALSE;  // For linear tables
+    if (Zeros > (nEntries / 4)) return TRUE;  // Degenerated, mostly zeros
+    if (Poles > (nEntries / 4)) return TRUE;  // Degenerated, mostly poles
+
+    return FALSE;
+}
+
 // --------------------------------------------------------------------------------------------------------------
 // We need xput over here
 
@@ -917,6 +967,7 @@
     cmsStage* OptimizedCLUTmpe;
     cmsColorSpaceSignature ColorSpace, OutputColorSpace;
     cmsStage* OptimizedPrelinMpe;
+    cmsStage* mpe;
     cmsToneCurve**   OptimizedPrelinCurves;
     _cmsStageCLutData*     OptimizedPrelinCLUT;
 
@@ -935,6 +986,14 @@
     }
 
     OriginalLut = *Lut;
+
+   // Named color pipelines cannot be optimized either
+   for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
+         mpe != NULL;
+         mpe = cmsStageNext(mpe)) {
+            if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
+    }
+
     ColorSpace       = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat));
     OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat));
     nGridPoints      = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
@@ -981,6 +1040,9 @@
         // Exclude if non-monotonic
         if (!cmsIsToneCurveMonotonic(Trans[t]))
             lIsSuitable = FALSE;
+
+        if (IsDegenerated(Trans[t]))
+            lIsSuitable = FALSE;
     }
 
     // If it is not suitable, just quit
@@ -1413,12 +1475,12 @@
             // first we compute the resulting byte and then we store the byte times
             // 257. This quantization allows to round very quick by doing a >> 8, but
             // since the low byte is always equal to msb, we can do a & 0xff and this works!
-            cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0 + 0.5);
+            cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0);
             cmsUInt8Number  b = FROM_16_TO_8(w);
 
             Table[i] = FROM_8_TO_16(b);
         }
-        else Table[i]  = _cmsQuickSaturateWord(Val * 65535.0 + 0.5);
+        else Table[i]  = _cmsQuickSaturateWord(Val * 65535.0);
     }
 }
 
@@ -1655,3 +1717,5 @@
     return AnySuccess;
 }
 
+
+
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c	2013-12-19 12:21:25.971481609 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c	2013-12-19 12:23:00.744901214 +0000
@@ -57,8 +57,8 @@
 
 // This module handles all formats supported by lcms. There are two flavors, 16 bits and
 // floating point. Floating point is supported only in a subset, those formats holding
-// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component as special
-// case)
+// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component
+// as special case)
 
 // ---------------------------------------------------------------------------
 
@@ -73,9 +73,7 @@
 // * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256
 cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x)
 {
-    int a;
-
-    a = (x << 8 | x) >> 8;  // * 257 / 256
+    int a = (x << 8 | x) >> 8;  // * 257 / 256
     if ( a > 0xffff) return 0xffff;
     return (cmsUInt16Number) a;
 }
@@ -90,17 +88,18 @@
 typedef struct {
     cmsUInt32Number Type;
     cmsUInt32Number Mask;
-    cmsFormatter16 Frm;
+    cmsFormatter16  Frm;
 
 } cmsFormatters16;
 
 typedef struct {
     cmsUInt32Number    Type;
     cmsUInt32Number    Mask;
-    cmsFormatterFloat Frm;
+    cmsFormatterFloat  Frm;
 
 } cmsFormattersFloat;
 
+
 #define ANYSPACE        COLORSPACE_SH(31)
 #define ANYCHANNELS     CHANNELS_SH(15)
 #define ANYEXTRA        EXTRA_SH(7)
@@ -119,6 +118,7 @@
 
 // Unpacking routines (16 bits) ----------------------------------------------------------------------------------------
 
+
 // Does almost everything but is slow
 static
 cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info,
@@ -131,7 +131,7 @@
     int Reverse    = T_FLAVOR(info ->InputFormat);
     int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
     int Extra      = T_EXTRA(info -> InputFormat);
-    int ExtraFirst = DoSwap && !SwapFirst;
+    int ExtraFirst = DoSwap ^ SwapFirst;
     cmsUInt16Number v;
     int i;
 
@@ -160,6 +160,10 @@
     }
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
+
 }
 
 // Extra channels are just ignored because come in the next planes
@@ -169,13 +173,14 @@
                                   register cmsUInt8Number* accum,
                                   register cmsUInt32Number Stride)
 {
-    int nChan = T_CHANNELS(info -> InputFormat);
-    int DoSwap= T_DOSWAP(info ->InputFormat);
-    int Reverse= T_FLAVOR(info ->InputFormat);
+    int nChan     = T_CHANNELS(info -> InputFormat);
+    int DoSwap    = T_DOSWAP(info ->InputFormat);
+    int SwapFirst = T_SWAPFIRST(info ->InputFormat);
+    int Reverse   = T_FLAVOR(info ->InputFormat);
     int i;
     cmsUInt8Number* Init = accum;
 
-    if (DoSwap) {
+    if (DoSwap ^ SwapFirst) {
         accum += T_EXTRA(info -> InputFormat) * Stride;
     }
 
@@ -204,6 +209,9 @@
     wIn[3] = FROM_8_TO_16(*accum); accum++; // K
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -218,6 +226,9 @@
     wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -232,6 +243,9 @@
     wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // KYMC
@@ -247,6 +261,9 @@
     wIn[0] = FROM_8_TO_16(*accum); accum++;  // C
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -261,6 +278,9 @@
     wIn[3] = FROM_8_TO_16(*accum); accum++;  // C
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -274,6 +294,9 @@
     wIn[2] = FROM_8_TO_16(*accum); accum++;     // B
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -288,6 +311,9 @@
     wIn[0] = FROM_8_TO_16(*accum); accum++; // R
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -302,6 +328,9 @@
     wIn[2] = FROM_8_TO_16(*accum); accum++; // B
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -317,6 +346,9 @@
     wIn[0] = FROM_8_TO_16(*accum); accum++;     // R
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -330,6 +362,9 @@
     wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -344,6 +379,9 @@
     wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -357,34 +395,30 @@
     wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // b
 
     return accum;
-}
-
 
-
-// Monochrome + alpha. Alpha is lost
-static
-cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info,
-                             register cmsUInt16Number wIn[],
-                             register cmsUInt8Number* accum,
-                             register cmsUInt32Number Stride)
-{
-    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
-    wIn[3] = FROM_8_TO_16(*accum); accum++;                       // alpha
-    return accum;
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
+// for duplex
 static
-cmsUInt8Number* Unroll2ByteSwapFirst(register _cmsTRANSFORM* info,
+cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info,
                                      register cmsUInt16Number wIn[],
                                      register cmsUInt8Number* accum,
                                      register cmsUInt32Number Stride)
 {
-    wIn[3] = FROM_8_TO_16(*accum); accum++;                       // alpha
-    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
+    wIn[0] = FROM_8_TO_16(*accum); accum++;     // ch1
+    wIn[1] = FROM_8_TO_16(*accum); accum++;     // ch2
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
+
+
 // Monochrome duplicates L into RGB for null-transforms
 static
 cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info,
@@ -393,7 +427,27 @@
                             register cmsUInt32Number Stride)
 {
     wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
+
+    return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
+}
+
+
+static
+cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info,
+                                 register cmsUInt16Number wIn[],
+                                 register cmsUInt8Number* accum,
+                                 register cmsUInt32Number Stride)
+{
+    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
+    accum += 1;
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -404,7 +458,11 @@
 {
     wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
     accum += 2;
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -414,7 +472,11 @@
                                     register cmsUInt32Number Stride)
 {
     wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++;     // L
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -430,7 +492,7 @@
     int Reverse     = T_FLAVOR(info ->InputFormat);
     int SwapFirst   = T_SWAPFIRST(info -> InputFormat);
     int Extra       = T_EXTRA(info -> InputFormat);
-    int ExtraFirst  = DoSwap && !SwapFirst;
+    int ExtraFirst  = DoSwap ^ SwapFirst;
     int i;
 
     if (ExtraFirst) {
@@ -463,6 +525,8 @@
     }
 
     return accum;
+
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -511,6 +575,9 @@
     wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -525,6 +592,9 @@
     wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -539,6 +609,9 @@
     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // KYMC
@@ -554,6 +627,9 @@
     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -568,6 +644,9 @@
     wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -579,7 +658,11 @@
     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -591,7 +674,11 @@
     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -606,6 +693,9 @@
     wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -620,6 +710,9 @@
     wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -629,7 +722,11 @@
                             register cmsUInt32Number Stride)
 {
     wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;   // L
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -639,7 +736,11 @@
                                     register cmsUInt32Number Stride)
 {
     wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2;
+
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -651,33 +752,29 @@
     wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum;
 
     accum += 8;
-    return accum;
-}
-
-static
-cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info,
-                             register cmsUInt16Number wIn[],
-                             register cmsUInt8Number* accum,
-                             register cmsUInt32Number Stride)
-{
-    wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;   // L
-    wIn[3] = *(cmsUInt16Number*) accum; accum += 2;                    // alpha
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Unroll2WordSwapFirst(register _cmsTRANSFORM* info,
+cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info,
                                      register cmsUInt16Number wIn[],
                                      register cmsUInt8Number* accum,
                                      register cmsUInt32Number Stride)
 {
-    wIn[3] = *(cmsUInt16Number*) accum; accum += 2;                    // alpha
-    wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;   // L
+    wIn[0] = *(cmsUInt16Number*) accum; accum += 2;    // ch1
+    wIn[1] = *(cmsUInt16Number*) accum; accum += 2;    // ch2
 
     return accum;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
+
 // This is a conversion of Lab double to 16 bits
 static
 cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info,
@@ -701,7 +798,41 @@
     else {
 
         cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum);
-        accum += sizeof(cmsCIELab);
+        accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
+        return accum;
+    }
+}
+
+
+// This is a conversion of Lab float to 16 bits
+static
+cmsUInt8Number* UnrollLabFloatTo16(register _cmsTRANSFORM* info,
+                                    register cmsUInt16Number wIn[],
+                                    register cmsUInt8Number* accum,
+                                    register cmsUInt32Number  Stride)
+{
+    cmsCIELab Lab;
+
+    if (T_PLANAR(info -> InputFormat)) {
+
+        cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
+
+
+        Lab.L = Pt[0];
+        Lab.a = Pt[Stride];
+        Lab.b = Pt[Stride*2];
+
+        cmsFloat2LabEncoded(wIn, &Lab);
+        return accum + sizeof(cmsFloat32Number);
+    }
+    else {
+
+        Lab.L = ((cmsFloat32Number*) accum)[0];
+        Lab.a = ((cmsFloat32Number*) accum)[1];
+        Lab.b = ((cmsFloat32Number*) accum)[2];
+
+        cmsFloat2LabEncoded(wIn, &Lab);
+        accum += (3 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
         return accum;
     }
 }
@@ -729,7 +860,7 @@
 
     else {
         cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum);
-        accum += sizeof(cmsCIEXYZ);
+        accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
 
         return accum;
     }
@@ -761,65 +892,117 @@
 // Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits
 static
 cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info,
-                                 register cmsUInt16Number wIn[],
-                                 register cmsUInt8Number* accum,
-                                 register cmsUInt32Number Stride)
+                                register cmsUInt16Number wIn[],
+                                register cmsUInt8Number* accum,
+                                register cmsUInt32Number Stride)
 {
-    cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
-    int nChan  = T_CHANNELS(info -> InputFormat);
-    int Planar = T_PLANAR(info -> InputFormat);
-    int i;
+
+    int nChan      = T_CHANNELS(info -> InputFormat);
+    int DoSwap     = T_DOSWAP(info ->InputFormat);
+    int Reverse    = T_FLAVOR(info ->InputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
+    int Extra      = T_EXTRA(info -> InputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    int Planar     = T_PLANAR(info -> InputFormat);
     cmsFloat64Number v;
-    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+    cmsUInt16Number  vi;
+    int i, start = 0;
+   cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+
+
+    if (ExtraFirst)
+            start = Extra;
 
     for (i=0; i < nChan; i++) {
 
-        if (Planar)
+        int index = DoSwap ? (nChan - i - 1) : i;
 
-            v = Inks[i * Stride];
+        if (Planar)
+            v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride];
         else
-            v = Inks[i];
+            v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start];
+
+        vi = _cmsQuickSaturateWord(v * maximum);
+
+        if (Reverse)
+            vi = REVERSE_FLAVOR_16(vi);
+
+        wIn[index] = vi;
+    }
 
-        wIn[i] = _cmsQuickSaturateWord(v * maximum);
+
+    if (Extra == 0 && SwapFirst) {
+        cmsUInt16Number tmp = wIn[0];
+
+        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
+        wIn[nChan-1] = tmp;
     }
 
     if (T_PLANAR(info -> InputFormat))
         return accum + sizeof(cmsFloat64Number);
     else
-        return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number);
+        return accum + (nChan + Extra) * sizeof(cmsFloat64Number);
 }
 
+
+
 static
 cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info,
                                 register cmsUInt16Number wIn[],
                                 register cmsUInt8Number* accum,
                                 register cmsUInt32Number Stride)
 {
-    cmsFloat32Number* Inks = (cmsFloat32Number*) accum;
-    int nChan  = T_CHANNELS(info -> InputFormat);
-    int Planar = T_PLANAR(info -> InputFormat);
-    int i;
+
+    int nChan      = T_CHANNELS(info -> InputFormat);
+    int DoSwap     = T_DOSWAP(info ->InputFormat);
+    int Reverse    = T_FLAVOR(info ->InputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
+    int Extra      = T_EXTRA(info -> InputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    int Planar     = T_PLANAR(info -> InputFormat);
     cmsFloat32Number v;
-    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+    cmsUInt16Number  vi;
+    int i, start = 0;
+   cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+
+
+    if (ExtraFirst)
+            start = Extra;
 
     for (i=0; i < nChan; i++) {
 
-        if (Planar)
+        int index = DoSwap ? (nChan - i - 1) : i;
 
-            v = Inks[i * Stride];
+        if (Planar)
+            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
         else
-            v = Inks[i];
+            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
+
+        vi = _cmsQuickSaturateWord(v * maximum);
+
+        if (Reverse)
+            vi = REVERSE_FLAVOR_16(vi);
+
+        wIn[index] = vi;
+    }
+
+
+    if (Extra == 0 && SwapFirst) {
+        cmsUInt16Number tmp = wIn[0];
 
-        wIn[i] = _cmsQuickSaturateWord(v * maximum);
+        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
+        wIn[nChan-1] = tmp;
     }
 
     if (T_PLANAR(info -> InputFormat))
         return accum + sizeof(cmsFloat32Number);
     else
-        return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
+        return accum + (nChan + Extra) * sizeof(cmsFloat32Number);
 }
 
 
+
+
 // For 1 channel, we need to duplicate data (it comes in 0..1.0 range)
 static
 cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info,
@@ -832,12 +1015,13 @@
     wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0);
 
     return accum + sizeof(cmsFloat64Number);
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 //-------------------------------------------------------------------------------------------------------------------
 
-// True cmsFloat32Number transformation.
-
 // For anything going from cmsFloat32Number
 static
 cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
@@ -845,55 +1029,104 @@
                                     cmsUInt8Number* accum,
                                     cmsUInt32Number Stride)
 {
-    cmsFloat32Number* Inks = (cmsFloat32Number*) accum;
-    int nChan  = T_CHANNELS(info -> InputFormat);
-    int Planar = T_PLANAR(info -> InputFormat);
-    int i;
-    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
+
+    int nChan      = T_CHANNELS(info -> InputFormat);
+    int DoSwap     = T_DOSWAP(info ->InputFormat);
+    int Reverse    = T_FLAVOR(info ->InputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
+    int Extra      = T_EXTRA(info -> InputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    int Planar     = T_PLANAR(info -> InputFormat);
+    cmsFloat32Number v;
+    int i, start = 0;
+    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
 
 
-    for (i=0; i <  nChan; i++) {
+    if (ExtraFirst)
+            start = Extra;
+
+    for (i=0; i < nChan; i++) {
+
+        int index = DoSwap ? (nChan - i - 1) : i;
 
         if (Planar)
-            wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum);
+            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
         else
-            wIn[i] = (cmsFloat32Number) (Inks[i] / maximum);
+            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
+
+        v /= maximum;
+
+        wIn[index] = Reverse ? 1 - v : v;
+    }
+
+
+    if (Extra == 0 && SwapFirst) {
+        cmsFloat32Number tmp = wIn[0];
+
+        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
+        wIn[nChan-1] = tmp;
     }
 
     if (T_PLANAR(info -> InputFormat))
         return accum + sizeof(cmsFloat32Number);
     else
-        return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
+        return accum + (nChan + Extra) * sizeof(cmsFloat32Number);
 }
 
 // For anything going from double
+
 static
 cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
-                                     cmsFloat32Number wIn[],
-                                     cmsUInt8Number* accum,
-                                     cmsUInt32Number Stride)
+                                    cmsFloat32Number wIn[],
+                                    cmsUInt8Number* accum,
+                                    cmsUInt32Number Stride)
 {
-    cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
-    int nChan  = T_CHANNELS(info -> InputFormat);
-    int Planar = T_PLANAR(info -> InputFormat);
-    int i;
+
+    int nChan      = T_CHANNELS(info -> InputFormat);
+    int DoSwap     = T_DOSWAP(info ->InputFormat);
+    int Reverse    = T_FLAVOR(info ->InputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
+    int Extra      = T_EXTRA(info -> InputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    int Planar     = T_PLANAR(info -> InputFormat);
+    cmsFloat64Number v;
+    int i, start = 0;
     cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
 
-    for (i=0; i <  nChan; i++) {
+
+    if (ExtraFirst)
+            start = Extra;
+
+    for (i=0; i < nChan; i++) {
+
+        int index = DoSwap ? (nChan - i - 1) : i;
 
         if (Planar)
-            wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum);
+            v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start)  * Stride];
         else
-            wIn[i] = (cmsFloat32Number) (Inks[i] / maximum);
+            v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start];
+
+        v /= maximum;
+
+        wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v);
+    }
+
+
+    if (Extra == 0 && SwapFirst) {
+        cmsFloat32Number tmp = wIn[0];
+
+        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
+        wIn[nChan-1] = tmp;
     }
 
     if (T_PLANAR(info -> InputFormat))
         return accum + sizeof(cmsFloat64Number);
     else
-        return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number);
+        return accum + (nChan + Extra) * sizeof(cmsFloat64Number);
 }
 
 
+
 // From Lab double to cmsFloat32Number
 static
 cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info,
@@ -913,11 +1146,11 @@
     }
     else {
 
-        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);             // from 0..100 to 0..1
+        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1
         wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
         wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
 
-        accum += sizeof(cmsFloat64Number)*3;
+        accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
         return accum;
     }
 }
@@ -933,7 +1166,7 @@
 
     if (T_PLANAR(info -> InputFormat)) {
 
-        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                            // from 0..100 to 0..1
+        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                 // from 0..100 to 0..1
         wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
         wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
 
@@ -941,16 +1174,17 @@
     }
     else {
 
-        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);             // from 0..100 to 0..1
+        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1
         wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
         wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
 
-        accum += sizeof(cmsFloat32Number)*3;
+        accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
         return accum;
     }
 }
 
 
+
 // 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
 static
 cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
@@ -974,7 +1208,7 @@
         wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
         wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
 
-        accum += sizeof(cmsFloat64Number)*3;
+        accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
         return accum;
     }
 }
@@ -1001,11 +1235,13 @@
         wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
         wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
 
-        accum += sizeof(cmsFloat32Number)*3;
+        accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
         return accum;
     }
 }
 
+
+
 // Packing routines -----------------------------------------------------------------------------------------------------------
 
 
@@ -1022,7 +1258,7 @@
     int Reverse    = T_FLAVOR(info ->OutputFormat);
     int Extra      = T_EXTRA(info -> OutputFormat);
     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
-    int ExtraFirst = DoSwap && !SwapFirst;
+    int ExtraFirst = DoSwap ^ SwapFirst;
     cmsUInt8Number* swap1;
     cmsUInt8Number v = 0;
     int i;
@@ -1057,6 +1293,8 @@
 
 
     return output;
+
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1073,7 +1311,7 @@
     int Reverse    = T_FLAVOR(info ->OutputFormat);
     int Extra      = T_EXTRA(info -> OutputFormat);
     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
-    int ExtraFirst = DoSwap && !SwapFirst;
+    int ExtraFirst = DoSwap ^ SwapFirst;
     cmsUInt16Number* swap1;
     cmsUInt16Number v = 0;
     int i;
@@ -1113,6 +1351,8 @@
 
 
     return output;
+
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1122,12 +1362,19 @@
                                 register cmsUInt8Number* output,
                                 register cmsUInt32Number Stride)
 {
-    int nChan = T_CHANNELS(info -> OutputFormat);
-    int DoSwap = T_DOSWAP(info ->OutputFormat);
-    int Reverse= T_FLAVOR(info ->OutputFormat);
+    int nChan     = T_CHANNELS(info -> OutputFormat);
+    int DoSwap    = T_DOSWAP(info ->OutputFormat);
+    int SwapFirst = T_SWAPFIRST(info ->OutputFormat);
+    int Reverse   = T_FLAVOR(info ->OutputFormat);
     int i;
     cmsUInt8Number* Init = output;
 
+
+    if (DoSwap ^ SwapFirst) {
+        output += T_EXTRA(info -> OutputFormat) * Stride;
+    }
+
+
     for (i=0; i < nChan; i++) {
 
         int index = DoSwap ? (nChan - i - 1) : i;
@@ -1138,6 +1385,8 @@
     }
 
     return (Init + 1);
+
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1194,6 +1443,9 @@
     *output++ = FROM_16_TO_8(wOut[5]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // KCMYcm
@@ -1212,6 +1464,9 @@
     *output++ = FROM_16_TO_8(wOut[0]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // CMYKcm
@@ -1235,6 +1490,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // KCMYcm
@@ -1258,6 +1516,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1273,6 +1534,9 @@
     *output++ = FROM_16_TO_8(wOut[3]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1287,6 +1551,9 @@
     *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3]));
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1302,6 +1569,9 @@
     *output++ = FROM_16_TO_8(wOut[2]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // ABGR
@@ -1317,6 +1587,9 @@
     *output++ = FROM_16_TO_8(wOut[0]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1331,6 +1604,9 @@
     *output++ = FROM_16_TO_8(wOut[3]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1349,6 +1625,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1367,6 +1646,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // ABGR
@@ -1386,6 +1668,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 // CMYK
@@ -1405,6 +1690,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1419,6 +1707,9 @@
     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1433,6 +1724,9 @@
     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1449,6 +1743,9 @@
     output += 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1462,6 +1759,9 @@
     *output++ = FROM_16_TO_8(wOut[2]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1475,6 +1775,9 @@
     *output++ = (wOut[2] & 0xFF);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1488,6 +1791,9 @@
     *output++ = FROM_16_TO_8(wOut[0]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1501,6 +1807,9 @@
     *output++ = (wOut[0] & 0xFF);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
@@ -1518,6 +1827,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1534,6 +1846,9 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
@@ -1550,10 +1865,13 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* info,
                                    register cmsUInt16Number wOut[],
                                    register cmsUInt8Number* output,
                                    register cmsUInt32Number Stride)
@@ -1564,10 +1882,13 @@
     output++;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info,
                                             register cmsUInt16Number wOut[],
                                             register cmsUInt8Number* output,
                                             register cmsUInt32Number Stride)
@@ -1578,11 +1899,14 @@
     output++;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* info,
                                             register cmsUInt16Number wOut[],
                                             register cmsUInt8Number* output,
                                             register cmsUInt32Number Stride)
@@ -1593,10 +1917,13 @@
     *output++ = FROM_16_TO_8(wOut[2]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* info,
                                                      register cmsUInt16Number wOut[],
                                                      register cmsUInt8Number* output,
                                                      register cmsUInt32Number Stride)
@@ -1607,10 +1934,13 @@
     *output++ = (wOut[2] & 0xFF);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* info,
                                        register cmsUInt16Number wOut[],
                                        register cmsUInt8Number* output,
                                        register cmsUInt32Number Stride)
@@ -1621,10 +1951,13 @@
     *output++ = FROM_16_TO_8(wOut[0]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info,
                                                 register cmsUInt16Number wOut[],
                                                 register cmsUInt8Number* output,
                                                 register cmsUInt32Number Stride)
@@ -1635,11 +1968,14 @@
     *output++ = (wOut[0] & 0xFF);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info,
                                                 register cmsUInt16Number wOut[],
                                                 register cmsUInt8Number* output,
                                                 register cmsUInt32Number Stride)
@@ -1650,10 +1986,13 @@
     output++;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* info,
                                                          register cmsUInt16Number wOut[],
                                                          register cmsUInt8Number* output,
                                                          register cmsUInt32Number Stride)
@@ -1664,10 +2003,13 @@
     output++;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* info,
                                    register cmsUInt16Number wOut[],
                                    register cmsUInt8Number* output,
                                    register cmsUInt32Number Stride)
@@ -1681,10 +2023,13 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* info,
                                        register cmsUInt16Number wOut[],
                                        register cmsUInt8Number* output,
                                        register cmsUInt32Number Stride)
@@ -1698,11 +2043,14 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* info,
                                             register cmsUInt16Number wOut[],
                                             register cmsUInt8Number* output,
                                             register cmsUInt32Number Stride)
@@ -1716,11 +2064,14 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info,
                                                 register cmsUInt16Number wOut[],
                                                 register cmsUInt8Number* output,
                                                 register cmsUInt32Number Stride)
@@ -1734,46 +2085,61 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 
 static
-cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* info,
                           register cmsUInt16Number wOut[],
                           register cmsUInt8Number* output,
                           register cmsUInt32Number Stride)
 {
     *output++ = FROM_16_TO_8(wOut[0]);
+
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* info,
                                   register cmsUInt16Number wOut[],
                                   register cmsUInt8Number* output,
                                   register cmsUInt32Number Stride)
 {
     *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0]));
+
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* info,
                                register cmsUInt16Number wOut[],
                                register cmsUInt8Number* output,
                                register cmsUInt32Number Stride)
 {
     *output++ = FROM_16_TO_8(wOut[0]);
     output++;
+
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* info,
                                         register cmsUInt16Number wOut[],
                                         register cmsUInt8Number* output,
                                         register cmsUInt32Number Stride)
@@ -1782,10 +2148,13 @@
     *output++ = FROM_16_TO_8(wOut[0]);
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* info,
                           register cmsUInt16Number wOut[],
                           register cmsUInt8Number* output,
                           register cmsUInt32Number Stride)
@@ -1794,11 +2163,14 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* info,
                                   register cmsUInt16Number wOut[],
                                   register cmsUInt8Number* output,
                                   register cmsUInt32Number Stride)
@@ -1807,10 +2179,13 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* info,
                                    register cmsUInt16Number wOut[],
                                    register cmsUInt8Number* output,
                                    register cmsUInt32Number Stride)
@@ -1819,11 +2194,14 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 static
-cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* info,
                                register cmsUInt16Number wOut[],
                                register cmsUInt8Number* output,
                                register cmsUInt32Number Stride)
@@ -1832,10 +2210,13 @@
     output+= 4;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 static
-cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* Info,
+cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* info,
                                         register cmsUInt16Number wOut[],
                                         register cmsUInt8Number* output,
                                         register cmsUInt32Number Stride)
@@ -1845,18 +2226,21 @@
     output+= 2;
 
     return output;
+
+    cmsUNUSED_PARAMETER(info);
+    cmsUNUSED_PARAMETER(Stride);
 }
 
 
 // Unencoded Float values -- don't try optimize speed
 static
-cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info,
+cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* info,
                                     register cmsUInt16Number wOut[],
                                     register cmsUInt8Number* output,
                                     register cmsUInt32Number Stride)
 {
 
-    if (T_PLANAR(Info -> OutputFormat)) {
+    if (T_PLANAR(info -> OutputFormat)) {
 
         cmsCIELab  Lab;
         cmsFloat64Number* Out = (cmsFloat64Number*) output;
@@ -1871,175 +2255,197 @@
     else {
 
         cmsLabEncoded2Float((cmsCIELab*) output, wOut);
-        return output + (sizeof(cmsCIELab) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
+        return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number));
     }
-
 }
 
+
 static
-cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info,
+cmsUInt8Number* PackLabFloatFrom16(register _cmsTRANSFORM* info,
                                     register cmsUInt16Number wOut[],
                                     register cmsUInt8Number* output,
                                     register cmsUInt32Number Stride)
 {
-    if (T_PLANAR(Info -> OutputFormat)) {
+    cmsCIELab  Lab;
+    cmsLabEncoded2Float(&Lab, wOut);
 
-        cmsCIEXYZ XYZ;
-        cmsFloat64Number* Out = (cmsFloat64Number*) output;
-        cmsXYZEncoded2Float(&XYZ, wOut);
+    if (T_PLANAR(info -> OutputFormat)) {
 
-        Out[0]                  = XYZ.X;
-        Out[Stride]   = XYZ.Y;
-        Out[Stride*2] = XYZ.Z;
+        cmsFloat32Number* Out = (cmsFloat32Number*) output;
 
-        return output + sizeof(cmsFloat64Number);
+        Out[0]        = (cmsFloat32Number)Lab.L;
+        Out[Stride]   = (cmsFloat32Number)Lab.a;
+        Out[Stride*2] = (cmsFloat32Number)Lab.b;
 
+        return output + sizeof(cmsFloat32Number);
     }
     else {
 
-        cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut);
+       ((cmsFloat32Number*) output)[0] = (cmsFloat32Number) Lab.L;
+       ((cmsFloat32Number*) output)[1] = (cmsFloat32Number) Lab.a;
+       ((cmsFloat32Number*) output)[2] = (cmsFloat32Number) Lab.b;
 
-        return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
+        return output + (3 + T_EXTRA(info ->OutputFormat)) * sizeof(cmsFloat32Number);
     }
 }
 
 static
-cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* Info,
-                                 register cmsUInt16Number wOut[],
-                                 register cmsUInt8Number* output,
-                                 register cmsUInt32Number Stride)
+cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info,
+                                    register cmsUInt16Number wOut[],
+                                    register cmsUInt8Number* output,
+                                    register cmsUInt32Number Stride)
 {
-    cmsFloat64Number* Inks = (cmsFloat64Number*) output;
-    int nChan = T_CHANNELS(Info -> OutputFormat);
-    int i;
-    cmsFloat64Number maximum = IsInkSpace(Info ->InputFormat) ? 655.35 : 65535.0;
-
     if (T_PLANAR(Info -> OutputFormat)) {
 
-        for (i=0; i <  nChan; i++) {
+        cmsCIEXYZ XYZ;
+        cmsFloat64Number* Out = (cmsFloat64Number*) output;
+        cmsXYZEncoded2Float(&XYZ, wOut);
 
-            Inks[i*Stride] = wOut[i] / maximum;
-        }
+        Out[0]        = XYZ.X;
+        Out[Stride]   = XYZ.Y;
+        Out[Stride*2] = XYZ.Z;
 
         return output + sizeof(cmsFloat64Number);
+
     }
     else {
 
-        for (i=0; i <  nChan; i++) {
-
-            Inks[i] = wOut[i] /  maximum;
-        }
-
+        cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut);
 
-        return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat64Number);
+        return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
     }
-
 }
 
 static
-cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* Info,
+cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
                                 register cmsUInt16Number wOut[],
                                 register cmsUInt8Number* output,
                                 register cmsUInt32Number Stride)
 {
-    cmsFloat32Number* Inks = (cmsFloat32Number*) output;
-    int nChan = T_CHANNELS(Info -> OutputFormat);
-    int i;
-    cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0;
+    int nChan      = T_CHANNELS(info -> OutputFormat);
+    int DoSwap     = T_DOSWAP(info ->OutputFormat);
+    int Reverse    = T_FLAVOR(info ->OutputFormat);
+    int Extra      = T_EXTRA(info -> OutputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
+    int Planar     = T_PLANAR(info -> OutputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0;
+    cmsFloat64Number v = 0;
+    cmsFloat64Number* swap1 = (cmsFloat64Number*) output;
+    int i, start = 0;
 
-    if (T_PLANAR(Info -> OutputFormat)) {
+    if (ExtraFirst)
+        start = Extra;
 
-        for (i=0; i <  nChan; i++) {
+    for (i=0; i < nChan; i++) {
 
-            Inks[i*Stride] = (cmsFloat32Number) (wOut[i] / maximum);
-        }
+        int index = DoSwap ? (nChan - i - 1) : i;
 
-        return output + sizeof(cmsFloat32Number);
-    }
-    else {
+        v = (cmsFloat64Number) wOut[index] / maximum;
 
-        for (i=0; i <  nChan; i++) {
+        if (Reverse)
+            v = maximum - v;
 
-            Inks[i] = (cmsFloat32Number) (wOut[i] /  maximum);
-        }
+        if (Planar)
+            ((cmsFloat64Number*) output)[(i + start)  * Stride]= v;
+        else
+            ((cmsFloat64Number*) output)[i + start] = v;
+    }
 
+    if (!ExtraFirst) {
+        output += Extra * sizeof(cmsFloat64Number);
+    }
 
-        return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat32Number);
+    if (Extra == 0 && SwapFirst) {
+
+         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
+        *swap1 = v;
     }
 
+    if (T_PLANAR(info -> OutputFormat))
+        return output + sizeof(cmsFloat64Number);
+    else
+        return output + nChan * sizeof(cmsFloat64Number);
+
 }
 
 
-// --------------------------------------------------------------------------------------------------------
-
 static
-cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info,
-                                          cmsFloat32Number wOut[],
-                                          cmsUInt8Number* output,
-                                          cmsUInt32Number Stride)
+cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info,
+                                register cmsUInt16Number wOut[],
+                                register cmsUInt8Number* output,
+                                register cmsUInt32Number Stride)
 {
     int nChan      = T_CHANNELS(info -> OutputFormat);
     int DoSwap     = T_DOSWAP(info ->OutputFormat);
     int Reverse    = T_FLAVOR(info ->OutputFormat);
     int Extra      = T_EXTRA(info -> OutputFormat);
     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
-    int ExtraFirst = DoSwap && !SwapFirst;
-    cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
-    cmsFloat32Number* swap1;
+    int Planar     = T_PLANAR(info -> OutputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0;
     cmsFloat64Number v = 0;
-    int i;
-
-    swap1 = (cmsFloat32Number*) output;
+    cmsFloat32Number* swap1 = (cmsFloat32Number*) output;
+    int i, start = 0;
 
-    if (ExtraFirst) {
-        output += Extra * sizeof(cmsFloat32Number);
-    }
+    if (ExtraFirst)
+        start = Extra;
 
     for (i=0; i < nChan; i++) {
 
         int index = DoSwap ? (nChan - i - 1) : i;
 
-        v = wOut[index] * maximum;
+        v = (cmsFloat64Number) wOut[index] / maximum;
 
         if (Reverse)
             v = maximum - v;
 
-        *(cmsFloat32Number*) output = (cmsFloat32Number) v;
-
-        output += sizeof(cmsFloat32Number);
+        if (Planar)
+            ((cmsFloat32Number*) output)[(i + start ) * Stride]= (cmsFloat32Number) v;
+        else
+            ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v;
     }
 
     if (!ExtraFirst) {
         output += Extra * sizeof(cmsFloat32Number);
     }
 
-    if (Extra == 0 && SwapFirst) {
+  if (Extra == 0 && SwapFirst) {
 
-        memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
+         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
         *swap1 = (cmsFloat32Number) v;
     }
 
-
-    return output;
+    if (T_PLANAR(info -> OutputFormat))
+        return output + sizeof(cmsFloat32Number);
+    else
+        return output + nChan * sizeof(cmsFloat32Number);
 }
 
+
+
+// --------------------------------------------------------------------------------------------------------
+
 static
-cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info,
-                                          cmsFloat32Number wOut[],
-                                          cmsUInt8Number* output,
-                                          cmsUInt32Number Stride)
+cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
+                                    cmsFloat32Number wOut[],
+                                    cmsUInt8Number* output,
+                                    cmsUInt32Number Stride)
 {
-    int nChan = T_CHANNELS(info -> OutputFormat);
-    int DoSwap = T_DOSWAP(info ->OutputFormat);
-    int Reverse= T_FLAVOR(info ->OutputFormat);
-    int i;
-    cmsUInt8Number* Init = output;
+    int nChan      = T_CHANNELS(info -> OutputFormat);
+    int DoSwap     = T_DOSWAP(info ->OutputFormat);
+    int Reverse    = T_FLAVOR(info ->OutputFormat);
+    int Extra      = T_EXTRA(info -> OutputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
+    int Planar     = T_PLANAR(info -> OutputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
-    cmsFloat64Number v;
+    cmsFloat32Number* swap1 = (cmsFloat32Number*) output;
+    cmsFloat64Number v = 0;
+    int i, start = 0;
 
-    if (DoSwap) {
-        output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat32Number);
-    }
+    if (ExtraFirst)
+        start = Extra;
 
     for (i=0; i < nChan; i++) {
 
@@ -2048,104 +2454,88 @@
         v = wOut[index] * maximum;
 
         if (Reverse)
-            v =  maximum - v;
+            v = maximum - v;
 
-        *(cmsFloat32Number*) output = (cmsFloat32Number) v;
-        output += (Stride * sizeof(cmsFloat32Number));
+        if (Planar)
+            ((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v;
+        else
+            ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v;
     }
 
-    return (Init + sizeof(cmsFloat32Number));
-}
+    if (!ExtraFirst) {
+        output += Extra * sizeof(cmsFloat32Number);
+    }
+
+   if (Extra == 0 && SwapFirst) {
 
+         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
+        *swap1 = (cmsFloat32Number) v;
+    }
+
+    if (T_PLANAR(info -> OutputFormat))
+        return output + sizeof(cmsFloat32Number);
+    else
+        return output + nChan * sizeof(cmsFloat32Number);
+}
 
 static
-cmsUInt8Number* PackChunkyDoublesFromFloat(_cmsTRANSFORM* info,
-                                           cmsFloat32Number wOut[],
-                                           cmsUInt8Number* output,
-                                           cmsUInt32Number Stride)
+cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
+                                    cmsFloat32Number wOut[],
+                                    cmsUInt8Number* output,
+                                    cmsUInt32Number Stride)
 {
     int nChan      = T_CHANNELS(info -> OutputFormat);
     int DoSwap     = T_DOSWAP(info ->OutputFormat);
     int Reverse    = T_FLAVOR(info ->OutputFormat);
     int Extra      = T_EXTRA(info -> OutputFormat);
     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
-    int ExtraFirst = DoSwap && !SwapFirst;
-    cmsFloat64Number* swap1;
+    int Planar     = T_PLANAR(info -> OutputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
     cmsFloat64Number v = 0;
-    int i;
+    cmsFloat64Number* swap1 = (cmsFloat64Number*) output;
+    int i, start = 0;
 
-    swap1 = (cmsFloat64Number*) output;
-
-    if (ExtraFirst) {
-        output += Extra * sizeof(cmsFloat64Number);
-    }
+    if (ExtraFirst)
+        start = Extra;
 
     for (i=0; i < nChan; i++) {
 
         int index = DoSwap ? (nChan - i - 1) : i;
 
-        v = (cmsFloat64Number) wOut[index] * maximum;
+        v = wOut[index] * maximum;
 
         if (Reverse)
             v = maximum - v;
 
-        *(cmsFloat64Number*) output = v;
-
-        output += sizeof(cmsFloat64Number);
+        if (Planar)
+            ((cmsFloat64Number*) output)[(i + start) * Stride] =  v;
+        else
+            ((cmsFloat64Number*) output)[i + start] =  v;
     }
 
     if (!ExtraFirst) {
         output += Extra * sizeof(cmsFloat64Number);
     }
 
-    if (Extra == 0 && SwapFirst) {
+   if (Extra == 0 && SwapFirst) {
 
-        memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
+         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
         *swap1 = v;
     }
 
 
-    return output;
-}
-
-static
-cmsUInt8Number* PackPlanarDoublesFromFloat(_cmsTRANSFORM* info,
-                                           cmsFloat32Number wOut[],
-                                           cmsUInt8Number* output,
-                                           cmsUInt32Number Stride)
-{
-    int nChan = T_CHANNELS(info -> OutputFormat);
-    int DoSwap = T_DOSWAP(info ->OutputFormat);
-    int Reverse= T_FLAVOR(info ->OutputFormat);
-    int i;
-    cmsUInt8Number* Init = output;
-    cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
-    cmsFloat64Number v;
-
-    if (DoSwap) {
-        output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat64Number);
-    }
-
-    for (i=0; i < nChan; i++) {
-
-        int index = DoSwap ? (nChan - i - 1) : i;
-
-        v = (cmsFloat64Number) wOut[index] * maximum;
-
-        if (Reverse)
-            v =  maximum - v;
-
-        *(cmsFloat64Number*) output = v;
-        output += (Stride * sizeof(cmsFloat64Number));
-    }
+    if (T_PLANAR(info -> OutputFormat))
+        return output + sizeof(cmsFloat64Number);
+    else
+        return output + nChan * sizeof(cmsFloat64Number);
 
-    return (Init + sizeof(cmsFloat64Number));
 }
 
 
 
 
+
 static
 cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
                                       cmsFloat32Number wOut[],
@@ -2156,7 +2546,7 @@
 
     if (T_PLANAR(Info -> OutputFormat)) {
 
-        Out[0]                  = (cmsFloat32Number) (wOut[0] * 100.0);
+        Out[0]        = (cmsFloat32Number) (wOut[0] * 100.0);
         Out[Stride]   = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
 
@@ -2173,6 +2563,7 @@
 
 }
 
+
 static
 cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
                                        cmsFloat32Number wOut[],
@@ -2183,7 +2574,7 @@
 
     if (T_PLANAR(Info -> OutputFormat)) {
 
-        Out[0]                  = (cmsFloat64Number) (wOut[0] * 100.0);
+        Out[0]        = (cmsFloat64Number) (wOut[0] * 100.0);
         Out[Stride]   = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
 
@@ -2212,7 +2603,7 @@
 
     if (T_PLANAR(Info -> OutputFormat)) {
 
-        Out[0]                  = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
+        Out[0]        = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
         Out[Stride]   = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
 
@@ -2229,7 +2620,6 @@
 
 }
 
-
 // Same, but convert to double
 static
 cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
@@ -2241,7 +2631,7 @@
 
     if (T_PLANAR(Info -> OutputFormat)) {
 
-        Out[0]                  = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
+        Out[0]        = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
         Out[Stride]   = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
 
@@ -2261,24 +2651,246 @@
 
 // ----------------------------------------------------------------------------------------------------------------
 
+#ifndef CMS_NO_HALF_SUPPORT
+
+// Decodes an stream of half floats to wIn[] described by input format
+
+static
+cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info,
+                                register cmsUInt16Number wIn[],
+                                register cmsUInt8Number* accum,
+                                register cmsUInt32Number Stride)
+{
+
+    int nChan      = T_CHANNELS(info -> InputFormat);
+    int DoSwap     = T_DOSWAP(info ->InputFormat);
+    int Reverse    = T_FLAVOR(info ->InputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
+    int Extra      = T_EXTRA(info -> InputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    int Planar     = T_PLANAR(info -> InputFormat);
+    cmsFloat32Number v;
+    int i, start = 0;
+    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F;
+
+
+    if (ExtraFirst)
+            start = Extra;
+
+    for (i=0; i < nChan; i++) {
+
+        int index = DoSwap ? (nChan - i - 1) : i;
+
+        if (Planar)
+            v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
+        else
+            v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
+
+        if (Reverse) v = maximum - v;
+
+        wIn[index] = _cmsQuickSaturateWord(v * maximum);
+    }
+
+
+    if (Extra == 0 && SwapFirst) {
+        cmsUInt16Number tmp = wIn[0];
+
+        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
+        wIn[nChan-1] = tmp;
+    }
+
+    if (T_PLANAR(info -> InputFormat))
+        return accum + sizeof(cmsUInt16Number);
+    else
+        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
+}
+
+// Decodes an stream of half floats to wIn[] described by input format
+
+static
+cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info,
+                                    cmsFloat32Number wIn[],
+                                    cmsUInt8Number* accum,
+                                    cmsUInt32Number Stride)
+{
+
+    int nChan      = T_CHANNELS(info -> InputFormat);
+    int DoSwap     = T_DOSWAP(info ->InputFormat);
+    int Reverse    = T_FLAVOR(info ->InputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
+    int Extra      = T_EXTRA(info -> InputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    int Planar     = T_PLANAR(info -> InputFormat);
+    cmsFloat32Number v;
+    int i, start = 0;
+    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
+
+
+    if (ExtraFirst)
+            start = Extra;
+
+    for (i=0; i < nChan; i++) {
+
+        int index = DoSwap ? (nChan - i - 1) : i;
+
+        if (Planar)
+            v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
+        else
+            v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
+
+        v /= maximum;
+
+        wIn[index] = Reverse ? 1 - v : v;
+    }
+
+
+    if (Extra == 0 && SwapFirst) {
+        cmsFloat32Number tmp = wIn[0];
+
+        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
+        wIn[nChan-1] = tmp;
+    }
+
+    if (T_PLANAR(info -> InputFormat))
+        return accum + sizeof(cmsUInt16Number);
+    else
+        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
+}
+
+
+static
+cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info,
+                                register cmsUInt16Number wOut[],
+                                register cmsUInt8Number* output,
+                                register cmsUInt32Number Stride)
+{
+    int nChan      = T_CHANNELS(info -> OutputFormat);
+    int DoSwap     = T_DOSWAP(info ->OutputFormat);
+    int Reverse    = T_FLAVOR(info ->OutputFormat);
+    int Extra      = T_EXTRA(info -> OutputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
+    int Planar     = T_PLANAR(info -> OutputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35F : 65535.0F;
+    cmsFloat32Number v = 0;
+    cmsUInt16Number* swap1 = (cmsUInt16Number*) output;
+    int i, start = 0;
+
+    if (ExtraFirst)
+        start = Extra;
+
+    for (i=0; i < nChan; i++) {
+
+        int index = DoSwap ? (nChan - i - 1) : i;
+
+        v = (cmsFloat32Number) wOut[index] / maximum;
+
+        if (Reverse)
+            v = maximum - v;
+
+        if (Planar)
+            ((cmsUInt16Number*) output)[(i + start ) * Stride]= _cmsFloat2Half(v);
+        else
+            ((cmsUInt16Number*) output)[i + start] =  _cmsFloat2Half(v);
+    }
+
+    if (!ExtraFirst) {
+        output += Extra * sizeof(cmsUInt16Number);
+    }
+
+  if (Extra == 0 && SwapFirst) {
+
+         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
+        *swap1 = _cmsFloat2Half(v);
+    }
+
+    if (T_PLANAR(info -> OutputFormat))
+        return output + sizeof(cmsUInt16Number);
+    else
+        return output + nChan * sizeof(cmsUInt16Number);
+}
+
+
+
+static
+cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
+                                    cmsFloat32Number wOut[],
+                                    cmsUInt8Number* output,
+                                    cmsUInt32Number Stride)
+{
+    int nChan      = T_CHANNELS(info -> OutputFormat);
+    int DoSwap     = T_DOSWAP(info ->OutputFormat);
+    int Reverse    = T_FLAVOR(info ->OutputFormat);
+    int Extra      = T_EXTRA(info -> OutputFormat);
+    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
+    int Planar     = T_PLANAR(info -> OutputFormat);
+    int ExtraFirst = DoSwap ^ SwapFirst;
+    cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0F : 1.0F;
+    cmsUInt16Number* swap1 = (cmsUInt16Number*) output;
+    cmsFloat32Number v = 0;
+    int i, start = 0;
+
+    if (ExtraFirst)
+        start = Extra;
+
+    for (i=0; i < nChan; i++) {
+
+        int index = DoSwap ? (nChan - i - 1) : i;
+
+        v = wOut[index] * maximum;
+
+        if (Reverse)
+            v = maximum - v;
+
+        if (Planar)
+            ((cmsUInt16Number*) output)[(i + start)* Stride]= _cmsFloat2Half( v );
+        else
+            ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half( v );
+    }
+
+    if (!ExtraFirst) {
+        output += Extra * sizeof(cmsUInt16Number);
+    }
+
+   if (Extra == 0 && SwapFirst) {
+
+         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
+        *swap1 = (cmsUInt16Number)  _cmsFloat2Half( v );
+    }
+
+    if (T_PLANAR(info -> OutputFormat))
+        return output + sizeof(cmsUInt16Number);
+    else
+        return output + nChan * sizeof(cmsUInt16Number);
+}
+
+#endif
+
+// ----------------------------------------------------------------------------------------------------------------
+
 
 static cmsFormatters16 InputFormatters16[] = {
 
     //    Type                                          Mask                  Function
     //  ----------------------------   ------------------------------------  ----------------------------
-    { TYPE_Lab_DBL,                                          ANYPLANAR,   UnrollLabDoubleTo16},
-    { TYPE_XYZ_DBL,                                          ANYPLANAR,   UnrollXYZDoubleTo16},
+    { TYPE_Lab_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollLabDoubleTo16},
+    { TYPE_XYZ_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleTo16},
+    { TYPE_Lab_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollLabFloatTo16},
     { TYPE_GRAY_DBL,                                                 0,   UnrollDouble1Chan},
-    { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
-    { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
-
+    { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
+                                             ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
+    { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
+                                             ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
+#ifndef CMS_NO_HALF_SUPPORT
+    { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
+                                            ANYEXTRA|ANYSWAP|ANYSPACE,   UnrollHalfTo16},
+#endif
 
     { CHANNELS_SH(1)|BYTES_SH(1),                              ANYSPACE,  Unroll1Byte},
+    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                  ANYSPACE,  Unroll1ByteSkip1},
     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2),                  ANYSPACE,  Unroll1ByteSkip2},
     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1ByteReversed},
-
-    { CHANNELS_SH(2)|BYTES_SH(1),                              ANYSPACE,  Unroll2Bytes},
-    { CHANNELS_SH(2)|BYTES_SH(1)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll2ByteSwapFirst},
+    { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1),              0,  Unroll2Bytes},
 
     { TYPE_LabV2_8,                                                   0,  UnrollLabV2_8 },
     { TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8 },
@@ -2295,17 +2907,17 @@
     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4BytesSwap},
     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4BytesSwapSwapFirst},
 
-    { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
-    { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
+    { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|
+                                   ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
 
+    { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
+                                           ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
 
     { CHANNELS_SH(1)|BYTES_SH(2),                              ANYSPACE,  Unroll1Word},
     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1WordReversed},
     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3),                  ANYSPACE,  Unroll1WordSkip3},
 
     { CHANNELS_SH(2)|BYTES_SH(2),                              ANYSPACE,  Unroll2Words},
-    { CHANNELS_SH(2)|BYTES_SH(2)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll2WordSwapFirst},
-
     { CHANNELS_SH(3)|BYTES_SH(2),                              ANYSPACE,  Unroll3Words},
     { CHANNELS_SH(4)|BYTES_SH(2),                              ANYSPACE,  Unroll4Words},
 
@@ -2318,7 +2930,7 @@
     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4WordsSwapSwapFirst},
 
 
-    { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords },
+    { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords},
     { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollAnyWords},
 };
 
@@ -2328,13 +2940,21 @@
 
     //    Type                                          Mask                  Function
     //  ----------------------------   ------------------------------------  ----------------------------
-    {     TYPE_Lab_DBL,                                                    ANYPLANAR,   UnrollLabDoubleToFloat},
-    {     TYPE_Lab_FLT,                                                    ANYPLANAR,   UnrollLabFloatToFloat},
-    {     TYPE_XYZ_DBL,                                                    ANYPLANAR,   UnrollXYZDoubleToFloat},
-    {     TYPE_XYZ_FLT,                                                    ANYPLANAR,   UnrollXYZFloatToFloat},
+    {     TYPE_Lab_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollLabDoubleToFloat},
+    {     TYPE_Lab_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollLabFloatToFloat},
 
-    {     FLOAT_SH(1)|BYTES_SH(4),           ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE,   UnrollFloatsToFloat},
-    {     FLOAT_SH(1)|BYTES_SH(0),           ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE,   UnrollDoublesToFloat},
+    {     TYPE_XYZ_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleToFloat},
+    {     TYPE_XYZ_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollXYZFloatToFloat},
+
+    {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
+                                                      ANYCHANNELS|ANYSPACE,  UnrollFloatsToFloat},
+
+    {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
+                                                        ANYCHANNELS|ANYSPACE,  UnrollDoublesToFloat},
+#ifndef CMS_NO_HALF_SUPPORT
+    {     FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
+                                                        ANYCHANNELS|ANYSPACE,  UnrollHalfToFloat},
+#endif
 };
 
 
@@ -2345,9 +2965,9 @@
     cmsUInt32Number i;
     cmsFormatter fr;
 
+    switch (dwFlags) {
 
-    if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) {
-
+    case CMS_PACK_FLAGS_16BITS: {
         for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
             cmsFormatters16* f = InputFormatters16 + i;
 
@@ -2357,7 +2977,9 @@
             }
         }
     }
-    else {
+    break;
+
+    case CMS_PACK_FLAGS_FLOAT: {
         for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
             cmsFormattersFloat* f = InputFormattersFloat + i;
 
@@ -2367,6 +2989,11 @@
             }
         }
     }
+    break;
+
+    default:;
+
+    }
 
     fr.Fmt16 = NULL;
     return fr;
@@ -2376,10 +3003,19 @@
     //    Type                                          Mask                  Function
     //  ----------------------------   ------------------------------------  ----------------------------
 
-    { TYPE_Lab_DBL,                                               ANYPLANAR,  PackLabDoubleFrom16},
-    { TYPE_XYZ_DBL,                                               ANYPLANAR,  PackXYZDoubleFrom16},
-    { FLOAT_SH(1)|BYTES_SH(0),      ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
-    { FLOAT_SH(1)|BYTES_SH(4),      ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
+    { TYPE_Lab_DBL,                                      ANYPLANAR|ANYEXTRA,  PackLabDoubleFrom16},
+    { TYPE_XYZ_DBL,                                      ANYPLANAR|ANYEXTRA,  PackXYZDoubleFrom16},
+
+    { TYPE_Lab_FLT,                                      ANYPLANAR|ANYEXTRA,  PackLabFloatFrom16},
+
+    { FLOAT_SH(1)|BYTES_SH(0),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
+                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
+    { FLOAT_SH(1)|BYTES_SH(4),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
+                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
+#ifndef CMS_NO_HALF_SUPPORT
+    { FLOAT_SH(1)|BYTES_SH(2),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
+                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackHalfFrom16},
+#endif
 
     { CHANNELS_SH(1)|BYTES_SH(1),                                  ANYSPACE,  Pack1Byte},
     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack1ByteSkip1},
@@ -2419,7 +3055,7 @@
     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),     ANYSPACE,  Pack4BytesSwapSwapFirst},
 
     { BYTES_SH(1),                 ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
-    { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
+    { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
 
     { CHANNELS_SH(1)|BYTES_SH(2),                                  ANYSPACE,  Pack1Word},
     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack1WordSkip1},
@@ -2453,50 +3089,65 @@
 static cmsFormattersFloat OutputFormattersFloat[] = {
     //    Type                                          Mask                                 Function
     //  ----------------------------   ---------------------------------------------------  ----------------------------
-    {     TYPE_Lab_FLT,                                                         ANYPLANAR,   PackLabFloatFromFloat},
-    {     TYPE_XYZ_FLT,                                                         ANYPLANAR,   PackXYZFloatFromFloat},
-    {     TYPE_Lab_DBL,                                                         ANYPLANAR,   PackLabDoubleFromFloat},
-    {     TYPE_XYZ_DBL,                                                         ANYPLANAR,   PackXYZDoubleFromFloat},
-    {     FLOAT_SH(1)|BYTES_SH(4),
-          ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackChunkyFloatsFromFloat },
-    {     FLOAT_SH(1)|BYTES_SH(4)|PLANAR_SH(1),             ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackPlanarFloatsFromFloat},
-    {     FLOAT_SH(1)|BYTES_SH(0),
-          ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackChunkyDoublesFromFloat },
-    {     FLOAT_SH(1)|BYTES_SH(0)|PLANAR_SH(1),             ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackPlanarDoublesFromFloat},
+    {     TYPE_Lab_FLT,                                                ANYPLANAR|ANYEXTRA,   PackLabFloatFromFloat},
+    {     TYPE_XYZ_FLT,                                                ANYPLANAR|ANYEXTRA,   PackXYZFloatFromFloat},
+
+    {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
+    {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
+
+    {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
+                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
+    {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
+                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
+#ifndef CMS_NO_HALF_SUPPORT
+    {     FLOAT_SH(1)|BYTES_SH(2),
+                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
+#endif
+
 
 
 };
 
 
 // Bit fields set to one in the mask are not compared
+static
 cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
 {
     cmsUInt32Number i;
     cmsFormatter fr;
 
 
-    if (dwFlags & CMS_PACK_FLAGS_FLOAT) {
+    switch (dwFlags)
+    {
 
-        for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
-            cmsFormattersFloat* f = OutputFormattersFloat + i;
+     case CMS_PACK_FLAGS_16BITS: {
+
+        for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
+            cmsFormatters16* f = OutputFormatters16 + i;
 
             if ((dwInput & ~f ->Mask) == f ->Type) {
-                fr.FmtFloat = f ->Frm;
+                fr.Fmt16 = f ->Frm;
                 return fr;
             }
         }
+        }
+        break;
 
-    }
-    else {
+    case CMS_PACK_FLAGS_FLOAT: {
 
-        for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
-            cmsFormatters16* f = OutputFormatters16 + i;
+        for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
+            cmsFormattersFloat* f = OutputFormattersFloat + i;
 
             if ((dwInput & ~f ->Mask) == f ->Type) {
-                fr.Fmt16 = f ->Frm;
+                fr.FmtFloat = f ->Frm;
                 return fr;
             }
         }
+        }
+        break;
+
+    default:;
+
     }
 
     fr.Fmt16 = NULL;
@@ -2523,8 +3174,8 @@
     // Reset
     if (Data == NULL) {
 
-        FactoryList = NULL;
-        return TRUE;
+          FactoryList = NULL;
+          return TRUE;
     }
 
     fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList));
@@ -2540,7 +3191,7 @@
 
 cmsFormatter _cmsGetFormatter(cmsUInt32Number Type,         // Specific type, i.e. TYPE_RGB_8
                              cmsFormatterDirection Dir,
-                             cmsUInt32Number dwFlags)       // Float or 16 bits
+                             cmsUInt32Number dwFlags)
 {
     cmsFormattersFactoryList* f;
 
@@ -2597,3 +3248,4 @@
     // Create a fake formatter for result
     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
 }
+
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c	2013-12-19 12:21:25.975481666 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c	2013-12-19 12:23:00.744901214 +0000
@@ -898,6 +898,7 @@
 {
     switch (ColorSpace) {
 
+    case cmsSig1colorData:
     case cmsSigGrayData: return 1;
 
     case cmsSig2colorData:  return 2;
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c	2013-12-19 12:21:25.975481666 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c	2013-12-19 12:23:00.748901273 +0000
@@ -105,12 +105,12 @@
 // 1 2 3 4 5 6 7 8
 // 8 7 6 5 4 3 2 1
 
-void CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord)
+void CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)
 {
 
 #ifndef CMS_USE_BIG_ENDIAN
 
-    cmsUInt8Number* pIn  = (cmsUInt8Number*) &QWord;
+    cmsUInt8Number* pIn  = (cmsUInt8Number*) QWord;
     cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
 
     _cmsAssert(Result != NULL);
@@ -128,7 +128,7 @@
 
     _cmsAssert(Result != NULL);
 
-    *Result = QWord;
+    *Result = *QWord;
 #endif
 }
 
@@ -218,7 +218,7 @@
     if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
             return FALSE;
 
-    if (n != NULL) _cmsAdjustEndianess64(n, tmp);
+    if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
     return TRUE;
 }
 
@@ -340,7 +340,7 @@
     return TRUE;
 }
 
-cmsBool CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
+cmsBool CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
 {
     cmsUInt64Number tmp;
 
@@ -568,7 +568,7 @@
 
             if (Plugin ->ExpectedVersion > LCMS_VERSION) {
                 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current  version is %d",
-                               Plugin ->ExpectedVersion, LCMS_VERSION);
+                    Plugin ->ExpectedVersion, LCMS_VERSION);
                 return FALSE;
             }
 
@@ -610,6 +610,10 @@
                     if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
                     break;
 
+                case cmsPluginTransformSig:
+                    if (!_cmsRegisterTransformPlugin(Plugin)) return FALSE;
+                    break;
+
                 default:
                     cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
                     return FALSE;
@@ -633,6 +637,7 @@
     _cmsRegisterParametricCurvesPlugin(NULL);
     _cmsRegisterMultiProcessElementPlugin(NULL);
     _cmsRegisterOptimizationPlugin(NULL);
+    _cmsRegisterTransformPlugin(NULL);
 
     if (PluginPool != NULL)
         _cmsSubAllocDestroy(PluginPool);
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c	2013-12-19 12:21:25.975481666 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c	2013-12-19 12:23:00.744901214 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2008 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -329,9 +329,9 @@
 static
 cmsUInt8Number L2Byte(cmsUInt16Number w)
 {
-        int ww = w + 0x0080;
+    int ww = w + 0x0080;
 
-        if (ww > 0xFFFF) return 0xFF;
+    if (ww > 0xFFFF) return 0xFF;
 
     return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF);
 }
@@ -498,6 +498,7 @@
     cmsUInt32Number i;
     cmsFloat64Number gamma;
 
+    if (Table == NULL) return; // Error
 
     if (Table ->nEntries <= 0) return;  // Empty table
 
@@ -577,6 +578,8 @@
 
     for( i=0; i < n; i++ )
     {
+        if (g[i] == NULL) return; // Error
+
         if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
 
             _cmsIOPrintf(m, "dup ");
@@ -674,6 +677,7 @@
           cmsUInt16Number wWordOut = Out[i];
           cmsUInt8Number wByteOut;           // Value as byte
 
+
           // We always deal with Lab4
 
           wByteOut = Word2Byte(wWordOut);
@@ -771,9 +775,9 @@
 
     for( i=0; i < 3; i++ ) {
 
-        _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[0 + 3*i],
-                     Matrix[1 + 3*i],
-                     Matrix[2 + 3*i]);
+        _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
+                                           Matrix[i + 3*1],
+                                           Matrix[i + 3*2]);
     }
 
 
@@ -857,21 +861,23 @@
 // Generates a curve from a gray profile
 
 static
-cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
+    cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
 {
     cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
     cmsHPROFILE hXYZ  = cmsCreateXYZProfile();
     cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);
     int i;
 
-    for (i=0; i < 256; i++) {
+    if (Out != NULL) {
+        for (i=0; i < 256; i++) {
 
-      cmsUInt8Number Gray = (cmsUInt8Number) i;
-      cmsCIEXYZ XYZ;
+            cmsUInt8Number Gray = (cmsUInt8Number) i;
+            cmsCIEXYZ XYZ;
 
-        cmsDoTransform(xform, &Gray, &XYZ, 1);
+            cmsDoTransform(xform, &Gray, &XYZ, 1);
 
-        Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
+            Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
+        }
     }
 
     cmsDeleteTransform(xform);
@@ -924,7 +930,7 @@
     switch (nChannels) {
 
     case 1: {
-        cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
+            cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
             EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50);
             cmsFreeToneCurve(Gray2Y);
             }
@@ -932,7 +938,7 @@
 
     case 3:
     case 4: {
-        cmsUInt32Number OutFrm = TYPE_Lab_16;
+            cmsUInt32Number OutFrm = TYPE_Lab_16;
             cmsPipeline* DeviceLink;
             _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
 
@@ -984,14 +990,23 @@
     if (ColorSpace == cmsSigGrayData) {
 
         cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
-            rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
+        rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
 
     }
     else
         if (ColorSpace == cmsSigRgbData) {
 
-            rc = EmitCIEBasedABC(m,  GetPtrToMatrix(Matrix),
-                                 _cmsStageGetPtrToCurveSet(Shaper),
+            cmsMAT3 Mat;
+            int i, j;
+
+            memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat));
+
+            for (i=0; i < 3; i++)
+                for (j=0; j < 3; j++)
+                    Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
+
+            rc = EmitCIEBasedABC(m,  (cmsFloat64Number *) &Mat,
+                                _cmsStageGetPtrToCurveSet(Shaper),
                                  &BlackPointAdaptedToD50);
         }
         else  {
@@ -1000,7 +1015,7 @@
             return 0;
         }
 
-    return rc;
+        return rc;
 }
 
 
@@ -1084,8 +1099,8 @@
         if (ColorSpace != cmsSigXYZData &&
             ColorSpace != cmsSigLabData) {
 
-            cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space");
-            goto Error;
+                cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space");
+                goto Error;
         }
 
 
@@ -1101,8 +1116,8 @@
 
         }
         else {
-            // We need a LUT for the rest
-            if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error;
+           // We need a LUT for the rest
+           if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error;
         }
     }
 
@@ -1211,7 +1226,7 @@
                       "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n"
                       "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n"
                       "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n",
-                         White.X, White.Y, White.Z);
+                      White.X, White.Y, White.Z);
             return;
         }
 
@@ -1534,24 +1549,25 @@
 
 
 cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID,
-                                                        cmsPSResourceType Type,
-                                                        cmsHPROFILE hProfile,
-                                                        cmsUInt32Number Intent,
-                                                        cmsUInt32Number dwFlags,
-                                                        cmsIOHANDLER* io)
+                                                               cmsPSResourceType Type,
+                                                               cmsHPROFILE hProfile,
+                                                               cmsUInt32Number Intent,
+                                                               cmsUInt32Number dwFlags,
+                                                               cmsIOHANDLER* io)
 {
     cmsUInt32Number  rc;
 
 
     switch (Type) {
 
-      case cmsPS_RESOURCE_CSA:
-          rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io);
-          break;
-      default:
-      case cmsPS_RESOURCE_CRD:
-          rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
-          break;
+        case cmsPS_RESOURCE_CSA:
+            rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io);
+            break;
+
+        default:
+        case cmsPS_RESOURCE_CRD:
+            rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
+            break;
     }
 
     return rc;
@@ -1560,7 +1576,7 @@
 
 
 cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID,
-                                              cmsHPROFILE hProfile,
+                              cmsHPROFILE hProfile,
                               cmsUInt32Number Intent, cmsUInt32Number dwFlags,
                               void* Buffer, cmsUInt32Number dwBufferLen)
 {
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c	2013-12-19 12:21:25.979481727 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c	2013-12-19 12:23:00.744901214 +0000
@@ -216,7 +216,6 @@
 // just that. There is a special flag for using black point tag, but turned
 // off by default because it is bogus on most profiles. The detection algorithm
 // involves to turn BP to neutral and to use only L component.
-
 cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
 {
 
@@ -292,3 +291,307 @@
     return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);
 }
 
+
+
+// ---------------------------------------------------------------------------------------------------------
+
+// Least Squares Fit of a Quadratic Curve to Data
+// http://www.personal.psu.edu/jhm/f90/lectures/lsq2.html
+
+static
+cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[], cmsFloat64Number y[])
+{
+    double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0;
+    double sum_y = 0, sum_yx = 0, sum_yx2 = 0;
+    double disc;
+    int i;
+    cmsMAT3 m;
+    cmsVEC3 v, res;
+
+    if (n < 4) return 0;
+
+    for (i=0; i < n; i++) {
+
+        double xn = x[i];
+        double yn = y[i];
+
+        sum_x  += xn;
+        sum_x2 += xn*xn;
+        sum_x3 += xn*xn*xn;
+        sum_x4 += xn*xn*xn*xn;
+
+        sum_y += yn;
+        sum_yx += yn*xn;
+        sum_yx2 += yn*xn*xn;
+    }
+
+    _cmsVEC3init(&m.v[0], n,      sum_x,  sum_x2);
+    _cmsVEC3init(&m.v[1], sum_x,  sum_x2, sum_x3);
+    _cmsVEC3init(&m.v[2], sum_x2, sum_x3, sum_x4);
+
+    _cmsVEC3init(&v, sum_y, sum_yx, sum_yx2);
+
+    if (!_cmsMAT3solve(&res, &m, &v)) return 0;
+
+    // y = t x2 + u x + c
+    // x = ( - u + Sqrt( u^2 - 4 t c ) ) / ( 2 t )
+    disc = res.n[1]*res.n[1] - 4.0 * res.n[0] * res.n[2];
+    if (disc < 0) return -1;
+
+    return ( -1.0 * res.n[1] + sqrt( disc )) / (2.0 * res.n[0]);
+}
+
+static
+cmsBool IsMonotonic(int n, const cmsFloat64Number Table[])
+{
+    int i;
+    cmsFloat64Number last;
+
+    last = Table[n-1];
+
+    for (i = n-2; i >= 0; --i) {
+
+        if (Table[i] > last)
+
+            return FALSE;
+        else
+            last = Table[i];
+
+    }
+
+    return TRUE;
+}
+
+// Calculates the black point of a destination profile.
+// This algorithm comes from the Adobe paper disclosing its black point compensation method.
+cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
+{
+    cmsColorSpaceSignature ColorSpace;
+    cmsHTRANSFORM hRoundTrip = NULL;
+    cmsCIELab InitialLab, destLab, Lab;
+
+    cmsFloat64Number MinL, MaxL;
+    cmsBool NearlyStraightMidRange = FALSE;
+    cmsFloat64Number L;
+    cmsFloat64Number x[101], y[101];
+    cmsFloat64Number lo, hi, NonMonoMin;
+    int n, l, i, NonMonoIndx;
+
+
+    // Make sure intent is adequate
+    if (Intent != INTENT_PERCEPTUAL &&
+        Intent != INTENT_RELATIVE_COLORIMETRIC &&
+        Intent != INTENT_SATURATION) {
+        BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+        return FALSE;
+    }
+
+
+    // v4 + perceptual & saturation intents does have its own black point, and it is
+    // well specified enough to use it. Black point tag is deprecated in V4.
+    if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) &&
+        (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {
+
+            // Matrix shaper share MRC & perceptual intents
+            if (cmsIsMatrixShaper(hProfile))
+                return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0);
+
+            // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents
+            BlackPoint -> X = cmsPERCEPTUAL_BLACK_X;
+            BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y;
+            BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z;
+            return TRUE;
+    }
+
+
+    // Check if the profile is lut based and gray, rgb or cmyk (7.2 in Adobe's document)
+    ColorSpace = cmsGetColorSpace(hProfile);
+    if (!cmsIsCLUT(hProfile, Intent, LCMS_USED_AS_OUTPUT ) ||
+        (ColorSpace != cmsSigGrayData &&
+         ColorSpace != cmsSigRgbData  &&
+         ColorSpace != cmsSigCmykData)) {
+
+        // In this case, handle as input case
+        return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags);
+    }
+
+    // It is one of the valid cases!, presto chargo hocus pocus, go for the Adobe magic
+
+    // Step 1
+    // ======
+
+    // Set a first guess, that should work on good profiles.
+    if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
+
+        cmsCIEXYZ IniXYZ;
+
+        // calculate initial Lab as source black point
+        if (!cmsDetectBlackPoint(&IniXYZ, hProfile, Intent, dwFlags)) {
+            return FALSE;
+        }
+
+        // convert the XYZ to lab
+        cmsXYZ2Lab(NULL, &InitialLab, &IniXYZ);
+
+    } else {
+
+        // set the initial Lab to zero, that should be the black point for perceptual and saturation
+        InitialLab.L = 0;
+        InitialLab.a = 0;
+        InitialLab.b = 0;
+    }
+
+
+    // Step 2
+    // ======
+
+    // Create a roundtrip. Define a Transform BT for all x in L*a*b*
+    hRoundTrip = CreateRoundtripXForm(hProfile, Intent);
+    if (hRoundTrip == NULL)  return FALSE;
+
+    // Calculate Min L*
+    Lab = InitialLab;
+    Lab.L = 0;
+    cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
+    MinL = destLab.L;
+
+    // Calculate Max L*
+    Lab = InitialLab;
+    Lab.L = 100;
+    cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
+    MaxL = destLab.L;
+
+    // Step 3
+    // ======
+
+    // check if quadratic estimation needs to be done.
+    if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
+
+        // Conceptually, this code tests how close the source l and converted L are to one another in the mid-range
+        // of the values. If the converted ramp of L values is close enough to a straight line y=x, then InitialLab
+        // is good enough to be the DestinationBlackPoint,
+        NearlyStraightMidRange = TRUE;
+
+        for (l=0; l <= 100; l++) {
+
+            Lab.L = l;
+            Lab.a = InitialLab.a;
+            Lab.b = InitialLab.b;
+
+            cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
+
+            L = destLab.L;
+
+            // Check the mid range in 20% after MinL
+            if (L > (MinL + 0.2 * (MaxL - MinL))) {
+
+                // Is close enough?
+                if (fabs(L - l) > 4.0) {
+
+                    // Too far away, profile is buggy!
+                    NearlyStraightMidRange = FALSE;
+                    break;
+                }
+            }
+        }
+    }
+    else {
+        // Check is always performed for perceptual and saturation intents
+        NearlyStraightMidRange = FALSE;
+    }
+
+
+    // If no furter checking is needed, we are done
+    if (NearlyStraightMidRange) {
+
+        cmsLab2XYZ(NULL, BlackPoint, &InitialLab);
+        cmsDeleteTransform(hRoundTrip);
+        return TRUE;
+    }
+
+    // The round-trip curve normally looks like a nearly constant section at the black point,
+    // with a corner and a nearly straight line to the white point.
+
+    // STEP 4
+    // =======
+
+    // find the black point using the least squares error quadratic curve fitting
+
+    if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
+        lo = 0.1;
+        hi = 0.5;
+    }
+    else {
+
+        // Perceptual and saturation
+        lo = 0.03;
+        hi = 0.25;
+    }
+
+    // Capture points for the fitting.
+    n = 0;
+    for (l=0; l <= 100; l++) {
+
+        cmsFloat64Number ff;
+
+        Lab.L = (cmsFloat64Number) l;
+        Lab.a = InitialLab.a;
+        Lab.b = InitialLab.b;
+
+        cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
+
+        ff = (destLab.L - MinL)/(MaxL - MinL);
+
+        if (ff >= lo && ff < hi) {
+
+            x[n] = Lab.L;
+            y[n] = ff;
+            n++;
+        }
+
+    }
+
+    // This part is not on the Adobe paper, but I found is necessary for getting any result.
+
+    if (IsMonotonic(n, y)) {
+
+        // Monotonic means lower point is stil valid
+        cmsLab2XYZ(NULL, BlackPoint, &InitialLab);
+        cmsDeleteTransform(hRoundTrip);
+        return TRUE;
+    }
+
+    // No suitable points, regret and use safer algorithm
+    if (n == 0) {
+        cmsDeleteTransform(hRoundTrip);
+        return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags);
+    }
+
+
+    NonMonoMin = 100;
+    NonMonoIndx = 0;
+    for (i=0; i < n; i++) {
+
+        if (y[i] < NonMonoMin) {
+            NonMonoIndx = i;
+            NonMonoMin = y[i];
+        }
+    }
+
+    Lab.L = x[NonMonoIndx];
+
+    // fit and get the vertex of quadratic curve
+    Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y);
+
+    if (Lab.L < 0.0 || Lab.L > 50.0) { // clip to zero L* if the vertex is negative
+        Lab.L = 0;
+    }
+
+    Lab.a = InitialLab.a;
+    Lab.b = InitialLab.b;
+
+    cmsLab2XYZ(NULL, BlackPoint, &Lab);
+
+    cmsDeleteTransform(hRoundTrip);
+    return TRUE;
+}
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c	2013-12-19 12:21:25.979481727 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -468,7 +468,8 @@
 int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[])
 {
     int nSectors = 0;
-    int i, a, t;
+    int a, t;
+    cmsUInt32Number i;
     cmsGDBPoint* pt;
 
     for (i=0; i < NSTEPS; i++) {
@@ -505,7 +506,7 @@
     cmsVEC3 Centre;
     cmsLine ray;
     int nCloseSectors;
-    cmsGDBPoint* Close[NSTEPS];
+    cmsGDBPoint* Close[NSTEPS + 1];
     cmsSpherical closel, templ;
     cmsLine edge;
     int k, m;
@@ -582,13 +583,13 @@
     _cmsAssert(hGBD != NULL);
 
     // Interpolate black
-    for (alpha = 0; alpha <= SECTORS; alpha++) {
+    for (alpha = 0; alpha < SECTORS; alpha++) {
 
         if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE;
     }
 
     // Interpolate white
-    for (alpha = 0; alpha <= SECTORS; alpha++) {
+    for (alpha = 0; alpha < SECTORS; alpha++) {
 
         if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE;
     }
@@ -596,7 +597,7 @@
 
     // Interpolate Mid
     for (theta = 1; theta < SECTORS; theta++) {
-        for (alpha = 0; alpha <= SECTORS; alpha++) {
+        for (alpha = 0; alpha < SECTORS; alpha++) {
 
             if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE;
         }
@@ -760,3 +761,4 @@
     return TRUE;
 }
 #endif
+
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c	2013-12-19 12:21:25.983481789 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -84,10 +84,10 @@
 #define DUP_FN(x)   Type_##x##_Dup
 
 // Helper macro to define a handler. Callbacks do have a fixed naming convention.
-#define TYPE_HANDLER(t, x)  { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x) }
+#define TYPE_HANDLER(t, x)  { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 }
 
 // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
-#define TYPE_MPE_HANDLER(t, x)  { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree }
+#define TYPE_MPE_HANDLER(t, x)  { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
 
 // Register a new type handler. This routine is shared between normal types and MPE
 static
@@ -154,7 +154,7 @@
     cmsUInt32Number i;
 
     _cmsAssert(io != NULL);
-    _cmsAssert(Array != NULL);
+    _cmsAssert(!(Array == NULL && n > 0));
 
     for (i=0; i < n; i++) {
         if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
@@ -163,6 +163,28 @@
     return TRUE;
 }
 
+static
+cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
+{
+    cmsUInt32Number i;
+    cmsUInt16Number tmp;
+
+    _cmsAssert(io != NULL);
+
+    for (i=0; i < n; i++) {
+
+        if (Array != NULL) {
+
+            if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
+            Array[i] = (wchar_t) tmp;
+        }
+        else {
+            if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
+        }
+
+    }
+    return TRUE;
+}
 
 // To deal with position tables
 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
@@ -171,8 +193,8 @@
                                              cmsUInt32Number n,
                                              cmsUInt32Number SizeOfTag);
 
-// Helper function to deal with position tables as decribed in several addendums to ICC spec 4.2
-// A table of n elements is written, where first comes n records containing offsets and sizes and
+// Helper function to deal with position tables as decribed in ICC spec 4.3
+// A table of n elements is readed, where first comes n records containing offsets and sizes and
 // then a block containing the data itself. This allows to reuse same data in more than one entry
 static
 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
@@ -224,7 +246,7 @@
 static
 cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
                                cmsIOHANDLER* io,
-                                cmsUInt32Number SizeOfTag,
+                               cmsUInt32Number SizeOfTag,
                                cmsUInt32Number Count,
                                cmsUInt32Number BaseOffset,
                                void *Cargo,
@@ -713,6 +735,8 @@
     *nItems = 0;
 
     // We need to store the "\0" at the end, so +1
+    if (SizeOfTag == UINT_MAX) goto Error;
+
     Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
     if (Text == NULL) goto Error;
 
@@ -807,13 +831,20 @@
     cmsUInt32Number LenOfData;
 
     *nItems = 0;
+
+    if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+
     LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
+    if (LenOfData > INT_MAX) return NULL;
 
     BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
     if (BinData == NULL) return NULL;
 
     BinData ->len = LenOfData;
-    if (!_cmsReadUInt32Number(io, &BinData->flag)) return NULL;
+    if (!_cmsReadUInt32Number(io, &BinData->flag)) {
+        _cmsFree(self ->ContextID, BinData);
+        return NULL;
+    }
 
     if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
 
@@ -1104,6 +1135,9 @@
 
            default:  // Curve
 
+               if (Count > 0x7FFF)
+                   return NULL; // This is to prevent bad guys for doing bad things
+
                NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
                if (!NewGamma) return NULL;
 
@@ -1219,17 +1253,23 @@
 cmsBool  Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
 {
     cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
-    int i, nParams;
+    int i, nParams, typen;
     static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
 
+    typen = Curve -> Segments[0].Type;
+
+    if (Curve ->nSegments > 1 || typen < 1) {
 
-    if (Curve ->nSegments > 1 || Curve -> Segments[0].Type < 1) {
+        cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
+        return FALSE;
+    }
 
-        cmsSignalError(self->ContextID, 0, "Multisegment or Inverted parametric curves cannot be written");
+    if (typen > 5) {
+        cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
         return FALSE;
     }
 
-    nParams = ParamsByType[Curve ->Segments[0].Type];
+    nParams = ParamsByType[typen];
 
     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
     if (!_cmsWriteUInt16Number(io, 0)) return FALSE;        // Reserved
@@ -1394,13 +1434,11 @@
 // ********************************************************************************
 // Type cmsSigMultiLocalizedUnicodeType
 // ********************************************************************************
-
 //
 //   Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
 //   Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
 //   taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
 //
-// FIXME: this doesn't work if sizeof(wchat_t) != 2  !!!
 
 static
 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
@@ -1410,7 +1448,7 @@
     cmsUInt32Number SizeOfHeader;
     cmsUInt32Number  Len, Offset;
     cmsUInt32Number  i;
-    cmsUInt16Number* Block;
+    wchar_t*         Block;
     cmsUInt32Number  BeginOfThisString, EndOfThisString, LargestPosition;
 
     *nItems = 0;
@@ -1438,12 +1476,17 @@
 
         // Now deal with Len and offset.
         if (!_cmsReadUInt32Number(io, &Len)) goto Error;
-        mlu ->Entries[i].Len = Len;
-
         if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
 
+        // Check for overflow
+        if (Offset < (SizeOfHeader + 8)) goto Error;
+
+        // True begin of the string
         BeginOfThisString = Offset - SizeOfHeader - 8;
-        mlu ->Entries[i].StrW = BeginOfThisString;
+
+        // Ajust to wchar_t elements
+        mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
+        mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
 
         // To guess maximum size, add offset + len
         EndOfThisString = BeginOfThisString + Len;
@@ -1452,15 +1495,22 @@
     }
 
     // Now read the remaining of tag and fill all strings. Substract the directory
-    SizeOfTag   = LargestPosition;
-
-    Block = (cmsUInt16Number*) _cmsMalloc(self ->ContextID, SizeOfTag);
-    if (Block == NULL) goto Error;
+    SizeOfTag   = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
+    if (SizeOfTag == 0)
+    {
+        Block = NULL;
+        NumOfWchar = 0;
 
-    NumOfWchar = SizeOfTag / sizeof(cmsUInt16Number);
+    }
+    else
+    {
+        Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
+        if (Block == NULL) goto Error;
+        NumOfWchar = SizeOfTag / sizeof(wchar_t);
+        if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
+    }
 
-    if (!_cmsReadUInt16Array(io, NumOfWchar, Block)) goto Error;
-    mlu ->MemPool = Block;
+    mlu ->MemPool  = Block;
     mlu ->PoolSize = SizeOfTag;
     mlu ->PoolUsed = SizeOfTag;
 
@@ -1476,9 +1526,18 @@
 cmsBool  Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
 {
     cmsMLU* mlu =(cmsMLU*) Ptr;
-    cmsUInt32Number HeaderSize, Offset;
+    cmsUInt32Number HeaderSize;
+    cmsUInt32Number  Len, Offset;
     int i;
 
+    if (Ptr == NULL) {
+
+          // Empty placeholder
+          if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+          if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
+          return TRUE;
+    }
+
     if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
     if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
 
@@ -1486,16 +1545,19 @@
 
     for (i=0; i < mlu ->UsedEntries; i++) {
 
-        if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
-        if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country))  return FALSE;
-        if (!_cmsWriteUInt32Number(io, mlu ->Entries[i].Len)) return FALSE;
+        Len    =  mlu ->Entries[i].Len;
+        Offset =  mlu ->Entries[i].StrW;
 
-        Offset =  mlu ->Entries[i].StrW + HeaderSize + 8;
+        Len    = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
+        Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
 
+        if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
+        if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country))  return FALSE;
+        if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
         if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
     }
 
-    if (!_cmsWriteUInt16Array(io, mlu ->PoolUsed / sizeof(cmsUInt16Number), (cmsUInt16Number*)  mlu ->MemPool)) return FALSE;
+    if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*)  mlu ->MemPool)) return FALSE;
 
     return TRUE;
 
@@ -1584,6 +1646,7 @@
     cmsToneCurve* Tables[cmsMAXCHANNELS];
 
     if (nChannels > cmsMAXCHANNELS) return FALSE;
+    if (nChannels <= 0) return FALSE;
 
     memset(Tables, 0, sizeof(Tables));
 
@@ -1604,6 +1667,7 @@
     }
 
     _cmsFree(ContextID, Temp);
+    Temp = NULL;
 
 
     mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
@@ -1658,12 +1722,28 @@
 }
 
 
+// Check overflow
 static
-unsigned int uipow(cmsUInt32Number a, cmsUInt32Number b) {
-    cmsUInt32Number rv = 1;
-    for (; b > 0; b--)
+size_t uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
+{
+    cmsUInt32Number rv = 1, rc;
+
+    if (a == 0) return 0;
+    if (n == 0) return 0;
+
+    for (; b > 0; b--) {
+
         rv *= a;
-    return rv;
+
+        // Check for overflow
+        if (rv > UINT_MAX / a) return (size_t) -1;
+
+    }
+
+    rc = rv * n;
+
+    if (rv != rc / n) return (size_t) -1;
+    return rc;
 }
 
 
@@ -1687,6 +1767,8 @@
     if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
     if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
 
+     if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
+
     // Padding
     if (!_cmsReadUInt8Number(io, NULL)) goto Error;
 
@@ -1722,8 +1804,9 @@
     // Get input tables
     if (!Read8bitTables(self ->ContextID, io,  NewLUT, InputChannels)) goto Error;
 
-    // Get 3D CLUT
-    nTabSize = (OutputChannels * uipow(CLUTpoints, InputChannels));
+    // Get 3D CLUT. Check the overflow....
+    nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
+    if (nTabSize == (size_t) -1) goto Error;
     if (nTabSize > 0) {
 
         cmsUInt16Number *PtrW, *T;
@@ -1850,15 +1933,18 @@
     // The prelinearization table
     if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
 
-    nTabSize = (NewLUT->OutputChannels * uipow(clutPoints, NewLUT ->InputChannels));
+    nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
+    if (nTabSize == (size_t) -1) return FALSE;
+    if (nTabSize > 0) {
 
-    // The 3D CLUT.
-    if (clut != NULL) {
+        // The 3D CLUT.
+        if (clut != NULL) {
 
-        for (j=0; j < nTabSize; j++) {
+            for (j=0; j < nTabSize; j++) {
 
-            val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
-            if (!_cmsWriteUInt8Number(io, val)) return FALSE;
+                val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
+                if (!_cmsWriteUInt8Number(io, val)) return FALSE;
+            }
         }
     }
 
@@ -1905,6 +1991,7 @@
     if (nEntries <= 0) return TRUE;
 
     // Check for malicious profiles
+    if (nEntries < 2) return FALSE;
     if (nChannels > cmsMAXCHANNELS) return FALSE;
 
     // Init table to zero
@@ -1979,13 +2066,12 @@
 
     if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
     if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
-    if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL;
+    if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL;   // 255 maximum
 
     // Padding
     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
 
     // Do some checking
-    if (CLUTpoints > 100) goto Error;
     if (InputChannels > cmsMAXCHANNELS)  goto Error;
     if (OutputChannels > cmsMAXCHANNELS) goto Error;
 
@@ -2006,7 +2092,6 @@
 
 
     // Only operates on 3 channels
-
     if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
 
         mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
@@ -2014,15 +2099,18 @@
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat);
     }
 
-    if (!_cmsReadUInt16Number(io, &InputEntries)) return NULL;
-    if (!_cmsReadUInt16Number(io, &OutputEntries)) return NULL;
+    if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error;
+    if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error;
 
+    if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error;
+    if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
 
     // Get input tables
     if (!Read16bitTables(self ->ContextID, io,  NewLUT, InputChannels, InputEntries)) goto Error;
 
     // Get 3D CLUT
-    nTabSize = (OutputChannels * uipow(CLUTpoints, InputChannels));
+    nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
+    if (nTabSize == (size_t) -1) goto Error;
     if (nTabSize > 0) {
 
         cmsUInt16Number *T;
@@ -2030,10 +2118,17 @@
         T  = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
         if (T  == NULL) goto Error;
 
-        if (!_cmsReadUInt16Array(io, nTabSize, T)) goto Error;
+        if (!_cmsReadUInt16Array(io, nTabSize, T)) {
+            _cmsFree(self ->ContextID, T);
+            goto Error;
+        }
 
         mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
-        if (mpeclut == NULL) goto Error;
+        if (mpeclut == NULL) {
+             _cmsFree(self ->ContextID, T);
+            goto Error;
+        }
+
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
         _cmsFree(self ->ContextID, T);
     }
@@ -2155,11 +2250,13 @@
         if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
     }
 
-    nTabSize = (OutputChannels * uipow(clutPoints, InputChannels));
-
-    // The 3D CLUT.
-    if (clut != NULL) {
-        if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
+    nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
+    if (nTabSize == (size_t) -1) return FALSE;
+    if (nTabSize > 0) {
+        // The 3D CLUT.
+        if (clut != NULL) {
+            if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
+        }
     }
 
     // The postlinearization table
@@ -2246,8 +2343,12 @@
     if (!io -> Seek(io, Offset)) return NULL;
     if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
 
-    for (i=0; i < cmsMAXCHANNELS; i++)
+
+    for (i=0; i < cmsMAXCHANNELS; i++) {
+
+        if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least
         GridPoints[i] = gridPoints8[i];
+    }
 
     if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
 
@@ -2256,6 +2357,8 @@
     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
 
     CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
+    if (CLUT == NULL) return NULL;
+
     Data = (_cmsStageCLutData*) CLUT ->Data;
 
     // Precision can be 1 or 2 bytes
@@ -2276,7 +2379,7 @@
             if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL;
     }
     else {
-        cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow precision of '%d'", Precision);
+        cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
         return NULL;
     }
 
@@ -2304,7 +2407,7 @@
                     char String[5];
 
                     _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
-                    cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow curve type '%s'", String);
+                    cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
                 }
                 return NULL;
     }
@@ -2313,26 +2416,30 @@
 
 // Read a set of curves from specific offset
 static
-cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int nCurves)
+cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves)
 {
     cmsToneCurve* Curves[cmsMAXCHANNELS];
-   int i;
-    cmsStage* Lin;
-
+    cmsUInt32Number i;
+    cmsStage* Lin = NULL;
 
     if (nCurves > cmsMAXCHANNELS) return FALSE;
 
     if (!io -> Seek(io, Offset)) return FALSE;
 
+    for (i=0; i < nCurves; i++)
+        Curves[i] = NULL;
+
     for (i=0; i < nCurves; i++) {
 
         Curves[i] = ReadEmbeddedCurve(self, io);
-        if (Curves[i] == NULL) return FALSE;
-        if (!_cmsReadAlignment(io)) return FALSE;
+        if (Curves[i] == NULL) goto Error;
+        if (!_cmsReadAlignment(io)) goto Error;
+
     }
 
     Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
 
+Error:
     for (i=0; i < nCurves; i++)
         cmsFreeToneCurve(Curves[i]);
 
@@ -2395,26 +2502,31 @@
 
     if (offsetA!= 0) {
         mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetC != 0) {
         mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetM != 0) {
         mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetMat != 0) {
         mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetB != 0) {
         mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
@@ -2441,9 +2553,19 @@
     if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
     if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
 
+    if (m ->Offset != NULL) {
+
     if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
     if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
     if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
+    }
+    else {
+        if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+        if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+        if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+
+    }
+
 
     return TRUE;
 
@@ -2468,7 +2590,8 @@
         // If this is a table-based curve, use curve type even on V4
         CurrentType = Type;
 
-        if (Curves[i] ->nSegments == 0)
+        if ((Curves[i] ->nSegments == 0)||
+            ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
             CurrentType = cmsSigCurveType;
         else
         if (Curves[i] ->Segments[0].Type < 0)
@@ -2491,7 +2614,7 @@
                     char String[5];
 
                     _cmsTagSignature2String(String, (cmsTagSignature) Type);
-                    cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow curve type '%s'", String);
+                    cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
                 }
                 return FALSE;
         }
@@ -2511,6 +2634,11 @@
     cmsUInt32Number i;
     _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
 
+    if (CLUT ->HasFloatValues) {
+         cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only");
+         return FALSE;
+    }
+
     memset(gridPoints, 0, sizeof(gridPoints));
     for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
         gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
@@ -2536,7 +2664,7 @@
             if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
         }
         else {
-             cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow precision of '%d'", Precision);
+             cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
             return FALSE;
         }
 
@@ -2694,26 +2822,31 @@
 
     if (offsetB != 0) {
         mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetMat != 0) {
         mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetM != 0) {
         mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetC != 0) {
         mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
     if (offsetA!= 0) {
         mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan);
+        if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
         cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
     }
 
@@ -2978,7 +3111,10 @@
     prefix[31] = suffix[31] = 0;
 
     v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
-    if (v == NULL) return NULL;
+    if (v == NULL) {
+        cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
+        return NULL;
+    }
 
     if (nDeviceCoords > cmsMAXCHANNELS) {
         cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
@@ -3076,6 +3212,13 @@
 // Type cmsSigProfileSequenceDescType
 // ********************************************************************************
 
+// This type is an array of structures, each of which contains information from the
+// header fields and tags from the original profiles which were combined to create
+// the final profile. The order of the structures is the order in which the profiles
+// were combined and includes a structure for the final profile. This provides a
+// description of the profile sequence from source to destination,
+// typically used with the DeviceLink profile.
+
 static
 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
 {
@@ -3119,6 +3262,8 @@
     *nItems = 0;
 
     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+
+    if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
     SizeOfTag -= sizeof(cmsUInt32Number);
 
 
@@ -3133,40 +3278,42 @@
 
         cmsPSEQDESC* sec = &OutSeq -> seq[i];
 
-        if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) return NULL;
+        if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error;
+        if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
         SizeOfTag -= sizeof(cmsUInt32Number);
 
-        if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) return NULL;
+        if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error;
+        if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
         SizeOfTag -= sizeof(cmsUInt32Number);
 
-        if (!_cmsReadUInt64Number(io, &sec ->attributes)) return NULL;
+        if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error;
+        if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
         SizeOfTag -= sizeof(cmsUInt64Number);
 
-        if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) return NULL;
+        if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error;
+        if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
         SizeOfTag -= sizeof(cmsUInt32Number);
 
-        if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) return NULL;
-        if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) return NULL;
+        if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error;
+        if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error;
     }
 
     *nItems = 1;
     return OutSeq;
+
+Error:
+    cmsFreeProfileSequenceDescription(OutSeq);
+    return NULL;
 }
 
 
 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
+// and it depends of the version number passed on cmsTagDescriptor structure instead of stack
 static
 cmsBool  SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
 {
-    if (Text == NULL) {
-
-        // Placeholder for a null entry
-        if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
-        return Type_Text_Description_Write(self, io, NULL, 1);
-
-    }
+    if (self ->ICCVersion < 0x4000000) {
 
-    if (Text->UsedEntries <= 1) {
         if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
         return Type_Text_Description_Write(self, io, Text, 1);
     }
@@ -3191,7 +3338,7 @@
 
         if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
         if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
-        if (!_cmsWriteUInt64Number(io, sec ->attributes)) return FALSE;
+        if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
         if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
 
         if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
@@ -3366,26 +3513,33 @@
 
     // First curve is Under color removal
     if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
+    if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
     SizeOfTag -= sizeof(cmsUInt32Number);
 
     n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
     if (n ->Ucr == NULL) return NULL;
 
     if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
+    if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
     SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
 
     // Second curve is Black generation
     if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
+    if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
     SizeOfTag -= sizeof(cmsUInt32Number);
 
     n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
     if (n ->Bg == NULL) return NULL;
     if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
+    if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
     SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
+    if (SizeOfTag == UINT_MAX) return NULL;
 
     // Now comes the text. The length is specified by the tag size
     n ->Desc = cmsMLUalloc(self ->ContextID, 1);
-    ASCIIString = (char*) _cmsMalloc(self ->ContextID, sizeof(cmsUInt8Number)*(SizeOfTag + 1));
+    if (n ->Desc == NULL) return NULL;
+
+    ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
     if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
     ASCIIString[SizeOfTag] = 0;
     cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
@@ -3482,7 +3636,9 @@
 
     if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
 
+    if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
     if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
+
     Text     = (char*) _cmsMalloc(self ->ContextID, Count+1);
     if (Text == NULL) return FALSE;
 
@@ -3600,6 +3756,9 @@
     if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
     if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
 
+    if (sc ->nChannels > cmsMAXCHANNELS - 1)
+        sc ->nChannels = cmsMAXCHANNELS - 1;
+
     for (i=0; i < sc ->nChannels; i++) {
 
         if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
@@ -3778,6 +3937,7 @@
      if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
      if (!_cmsReadUInt16Number(io, NULL)) return NULL;
 
+     if (nSegments < 1) return NULL;
      Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
      if (Segments == NULL) return NULL;
 
@@ -4137,7 +4297,7 @@
 
     // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
     nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
-    for (i=0; i < nMaxGrids; i++) GridPoints[i] = Dimensions8[i];
+    for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
 
     // Allocate the true CLUT
     mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
@@ -4202,8 +4362,8 @@
 // This is the list of built-in MPE types
 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
 
-{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[1] },   // Ignore those elements for now
-{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[2] },   // (That's what the spec says)
+{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] },   // Ignore those elements for now
+{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] },   // (That's what the spec says)
 
 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType,     MPEcurve),      &SupportedMPEtypes[3] },
 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType,       MPEmatrix),     &SupportedMPEtypes[4] },
@@ -4466,6 +4626,11 @@
        if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
        if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
 
+       // Adobe's quirk fixup. Fixing broken profiles...
+       if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576)
+           nBytes = 2;
+
+
        // Populate tone curves
        for (n=0; n < 3; n++) {
 
@@ -4571,21 +4736,21 @@
         cmsGetToneCurveParametricType(Curves[1]) == 5 &&
         cmsGetToneCurveParametricType(Curves[2]) == 5) {
 
-        if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
+            if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
 
-        // Save parameters
-        for (i=0; i < 3; i++) {
+            // Save parameters
+            for (i=0; i < 3; i++) {
 
-            _cmsVCGTGAMMA v;
+                _cmsVCGTGAMMA v;
 
-            v.Gamma = Curves[i] ->Segments[0].Params[0];
-            v.Min   = Curves[i] ->Segments[0].Params[5];
-            v.Max   = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
-
-            if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
-            if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
-            if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
-        }
+                v.Gamma = Curves[i] ->Segments[0].Params[0];
+                v.Min   = Curves[i] ->Segments[0].Params[5];
+                v.Max   = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
+
+                if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
+                if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
+                if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
+            }
     }
 
     else {
@@ -4639,6 +4804,435 @@
     _cmsFree(self ->ContextID, Ptr);
 }
 
+
+// ********************************************************************************
+// Type cmsSigDictType
+// ********************************************************************************
+
+// Single column of the table can point to wchar or MLUC elements. Holds arrays of data
+typedef struct {
+    cmsContext ContextID;
+    cmsUInt32Number *Offsets;
+    cmsUInt32Number *Sizes;
+} _cmsDICelem;
+
+typedef struct {
+    _cmsDICelem Name, Value, DisplayName, DisplayValue;
+
+} _cmsDICarray;
+
+// Allocate an empty array element
+static
+cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e,  cmsUInt32Number Count)
+{
+    e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *));
+    if (e->Offsets == NULL) return FALSE;
+
+    e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *));
+    if (e->Sizes == NULL) {
+
+        _cmsFree(ContextID, e -> Offsets);
+        return FALSE;
+    }
+
+    e ->ContextID = ContextID;
+    return TRUE;
+}
+
+// Free an array element
+static
+void FreeElem(_cmsDICelem* e)
+{
+    if (e ->Offsets != NULL)  _cmsFree(e -> ContextID, e -> Offsets);
+    if (e ->Sizes   != NULL)  _cmsFree(e -> ContextID, e ->Sizes);
+    e->Offsets = e ->Sizes = NULL;
+}
+
+// Get rid of whole array
+static
+void FreeArray( _cmsDICarray* a)
+{
+    if (a ->Name.Offsets != NULL) FreeElem(&a->Name);
+    if (a ->Value.Offsets != NULL) FreeElem(&a ->Value);
+    if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName);
+    if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue);
+}
+
+
+// Allocate whole array
+static
+cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
+{
+    // Empty values
+    memset(a, 0, sizeof(_cmsDICarray));
+
+    // On depending on record size, create column arrays
+    if (!AllocElem(ContextID, &a ->Name, Count)) goto Error;
+    if (!AllocElem(ContextID, &a ->Value, Count)) goto Error;
+
+    if (Length > 16) {
+        if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error;
+
+    }
+    if (Length > 24) {
+        if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error;
+    }
+    return TRUE;
+
+Error:
+    FreeArray(a);
+    return FALSE;
+}
+
+// Read one element
+static
+cmsBool ReadOneElem(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset)
+{
+    if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
+    if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
+
+    // An offset of zero has special meaning and shal be preserved
+    if (e ->Offsets[i] > 0)
+        e ->Offsets[i] += BaseOffset;
+    return TRUE;
+}
+
+
+static
+cmsBool ReadOffsetArray(cmsIOHANDLER* io,  _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
+{
+    cmsUInt32Number i;
+
+    // Read column arrays
+    for (i=0; i < Count; i++) {
+
+        if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
+        if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
+
+        if (Length > 16) {
+
+            if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
+
+        }
+
+        if (Length > 24) {
+
+            if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+// Write one element
+static
+cmsBool WriteOneElem(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i)
+{
+    if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE;
+    if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE;
+
+    return TRUE;
+}
+
+static
+cmsBool WriteOffsetArray(cmsIOHANDLER* io,  _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
+{
+    cmsUInt32Number i;
+
+    for (i=0; i < Count; i++) {
+
+        if (!WriteOneElem(io, &a -> Name, i)) return FALSE;
+        if (!WriteOneElem(io, &a -> Value, i))  return FALSE;
+
+        if (Length > 16) {
+
+            if (!WriteOneElem(io, &a -> DisplayName, i))  return FALSE;
+        }
+
+        if (Length > 24) {
+
+            if (!WriteOneElem(io, &a -> DisplayValue, i))  return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+static
+cmsBool ReadOneWChar(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr)
+{
+
+    cmsUInt32Number nChars;
+
+      // Special case for undefined strings (see ICC Votable
+      // Proposal Submission, Dictionary Type and Metadata TAG Definition)
+      if (e -> Offsets[i] == 0) {
+
+          *wcstr = NULL;
+          return TRUE;
+      }
+
+      if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
+
+      nChars = e ->Sizes[i] / sizeof(cmsUInt16Number);
+
+
+      *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t));
+      if (*wcstr == NULL) return FALSE;
+
+      if (!_cmsReadWCharArray(io, nChars, *wcstr)) {
+          _cmsFree(e ->ContextID, *wcstr);
+          return FALSE;
+      }
+
+      // End of string marker
+      (*wcstr)[nChars] = 0;
+      return TRUE;
+}
+
+static
+cmsUInt32Number mywcslen(const wchar_t *s)
+{
+    const wchar_t *p;
+
+    p = s;
+    while (*p)
+        p++;
+
+    return (cmsUInt32Number)(p - s);
+}
+
+static
+cmsBool WriteOneWChar(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset)
+{
+    cmsUInt32Number Before = io ->Tell(io);
+    cmsUInt32Number n;
+
+    e ->Offsets[i] = Before - BaseOffset;
+
+    if (wcstr == NULL) {
+        e ->Sizes[i] = 0;
+        e ->Offsets[i] = 0;
+        return TRUE;
+    }
+
+    n = mywcslen(wcstr);
+    if (!_cmsWriteWCharArray(io,  n, wcstr)) return FALSE;
+
+    e ->Sizes[i] = io ->Tell(io) - Before;
+    return TRUE;
+}
+
+static
+cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu)
+{
+    cmsUInt32Number nItems = 0;
+
+    // A way to get null MLUCs
+    if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) {
+
+        *mlu = NULL;
+        return TRUE;
+    }
+
+    if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
+
+    *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]);
+    return *mlu != NULL;
+}
+
+static
+cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset)
+{
+    cmsUInt32Number Before;
+
+     // Special case for undefined strings (see ICC Votable
+     // Proposal Submission, Dictionary Type and Metadata TAG Definition)
+     if (mlu == NULL) {
+        e ->Sizes[i] = 0;
+        e ->Offsets[i] = 0;
+        return TRUE;
+    }
+
+    Before = io ->Tell(io);
+    e ->Offsets[i] = Before - BaseOffset;
+
+    if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
+
+    e ->Sizes[i] = io ->Tell(io) - Before;
+    return TRUE;
+}
+
+
+static
+void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+   cmsHANDLE hDict;
+   cmsUInt32Number i, Count, Length;
+   cmsUInt32Number BaseOffset;
+   _cmsDICarray a;
+   wchar_t *NameWCS = NULL, *ValueWCS = NULL;
+   cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
+   cmsBool rc;
+
+    *nItems = 0;
+
+    // Get actual position as a basis for element offsets
+    BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+    // Get name-value record count
+    if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+    SizeOfTag -= sizeof(cmsUInt32Number);
+
+    // Get rec lenghth
+    if (!_cmsReadUInt32Number(io, &Length)) return NULL;
+    SizeOfTag -= sizeof(cmsUInt32Number);
+
+    // Check for valid lengths
+    if (Length != 16 && Length != 24 && Length != 32) {
+         cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length);
+         return NULL;
+    }
+
+    // Creates an empty dictionary
+    hDict = cmsDictAlloc(self -> ContextID);
+    if (hDict == NULL) return NULL;
+
+    // On depending on record size, create column arrays
+    if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
+
+    // Read column arrays
+    if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
+
+    // Seek to each element and read it
+    for (i=0; i < Count; i++) {
+
+        if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error;
+        if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error;
+
+        if (Length > 16) {
+            if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error;
+        }
+
+        if (Length > 24) {
+            if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
+        }
+
+        rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
+
+        if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
+        if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
+        if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
+        if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
+
+        if (!rc) return FALSE;
+    }
+
+   FreeArray(&a);
+   *nItems = 1;
+   return (void*) hDict;
+
+Error:
+   FreeArray(&a);
+   cmsDictFree(hDict);
+   return NULL;
+}
+
+
+static
+cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+    cmsHANDLE hDict = (cmsHANDLE) Ptr;
+    const cmsDICTentry* p;
+    cmsBool AnyName, AnyValue;
+    cmsUInt32Number i, Count, Length;
+    cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset;
+   _cmsDICarray a;
+
+    if (hDict == NULL) return FALSE;
+
+    BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+    // Let's inspect the dictionary
+    Count = 0; AnyName = FALSE; AnyValue = FALSE;
+    for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) {
+
+        if (p ->DisplayName != NULL) AnyName = TRUE;
+        if (p ->DisplayValue != NULL) AnyValue = TRUE;
+        Count++;
+    }
+
+    Length = 16;
+    if (AnyName)  Length += 8;
+    if (AnyValue) Length += 8;
+
+    if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, Length)) return FALSE;
+
+    // Keep starting position of offsets table
+    DirectoryPos = io ->Tell(io);
+
+    // Allocate offsets array
+    if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error;
+
+    // Write a fake directory to be filled latter on
+    if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
+
+    // Write each element. Keep track of the size as well.
+    p = cmsDictGetEntryList(hDict);
+    for (i=0; i < Count; i++) {
+
+        if (!WriteOneWChar(io, &a.Name, i,  p ->Name, BaseOffset)) goto Error;
+        if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error;
+
+        if (p ->DisplayName != NULL) {
+            if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error;
+        }
+
+        if (p ->DisplayValue != NULL) {
+            if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
+        }
+
+       p = cmsDictNextEntry(p);
+    }
+
+    // Write the directory
+    CurrentPos = io ->Tell(io);
+    if (!io ->Seek(io, DirectoryPos)) goto Error;
+
+    if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
+
+    if (!io ->Seek(io, CurrentPos)) goto Error;
+
+    FreeArray(&a);
+    return TRUE;
+
+Error:
+    FreeArray(&a);
+    return FALSE;
+
+    cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+    return (void*)  cmsDictDup((cmsHANDLE) Ptr);
+
+    cmsUNUSED_PARAMETER(n);
+    cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+    cmsDictFree((cmsHANDLE) Ptr);
+    cmsUNUSED_PARAMETER(self);
+}
+
+
 // ********************************************************************************
 // Type support main routines
 // ********************************************************************************
@@ -4676,6 +5270,7 @@
 {TYPE_HANDLER(cmsCorbisBrokenXYZtype,          XYZ),                 &SupportedTagTypes[27] },
 {TYPE_HANDLER(cmsMonacoBrokenCurveType,        Curve),               &SupportedTagTypes[28] },
 {TYPE_HANDLER(cmsSigProfileSequenceIdType,     ProfileSequenceId),   &SupportedTagTypes[29] },
+{TYPE_HANDLER(cmsSigDictType,                  Dictionary),          &SupportedTagTypes[30] },
 {TYPE_HANDLER(cmsSigVcgtType,                  vcgt),                NULL }
 };
 
@@ -4795,6 +5390,7 @@
 
     { cmsSigScreeningTag,           { 1, 1, { cmsSigScreeningType},          NULL }, &SupportedTags[59]},
     { cmsSigVcgtTag,                { 1, 1, { cmsSigVcgtType},               NULL }, &SupportedTags[60]},
+    { cmsSigMetaTag,                { 1, 1, { cmsSigDictType},               NULL }, &SupportedTags[61]},
     { cmsSigProfileSequenceIdTag,   { 1, 1, { cmsSigProfileSequenceIdType},  NULL},  NULL}
 
 };
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c	2013-12-19 12:21:25.983481789 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c	2013-12-19 12:23:00.744901214 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -143,7 +143,7 @@
     if (!hICC)                          // can't allocate
         return NULL;
 
-    cmsSetProfileVersion(hICC, 4.2);
+    cmsSetProfileVersion(hICC, 4.3);
 
     cmsSetDeviceClass(hICC,      cmsSigDisplayClass);
     cmsSetColorSpace(hICC,       cmsSigRgbData);
@@ -247,7 +247,7 @@
     if (!hICC)                          // can't allocate
         return NULL;
 
-    cmsSetProfileVersion(hICC, 4.2);
+    cmsSetProfileVersion(hICC, 4.3);
 
     cmsSetDeviceClass(hICC,      cmsSigDisplayClass);
     cmsSetColorSpace(hICC,       cmsSigGrayData);
@@ -310,7 +310,7 @@
     if (!hICC)
         return NULL;
 
-    cmsSetProfileVersion(hICC, 4.2);
+    cmsSetProfileVersion(hICC, 4.3);
 
     cmsSetDeviceClass(hICC,      cmsSigLinkClass);
     cmsSetColorSpace(hICC,       ColorSpace);
@@ -429,7 +429,7 @@
     if (!hICC)                          // can't allocate
         return NULL;
 
-    cmsSetProfileVersion(hICC, 4.2);
+    cmsSetProfileVersion(hICC, 4.3);
 
     cmsSetDeviceClass(hICC,      cmsSigLinkClass);
     cmsSetColorSpace(hICC,       ColorSpace);
@@ -536,7 +536,7 @@
     hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
     if (hProfile == NULL) return NULL;
 
-    cmsSetProfileVersion(hProfile, 4.2);
+    cmsSetProfileVersion(hProfile, 4.3);
 
     cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
     cmsSetColorSpace(hProfile,  cmsSigLabData);
@@ -581,7 +581,7 @@
     hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL);
     if (hProfile == NULL) return NULL;
 
-    cmsSetProfileVersion(hProfile, 4.2);
+    cmsSetProfileVersion(hProfile, 4.3);
 
     cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
     cmsSetColorSpace(hProfile,  cmsSigXYZData);
@@ -835,7 +835,7 @@
     if (!hProfile)                          // can't allocate
         return NULL;
 
-    cmsSetProfileVersion(hProfile, 4.2);
+    cmsSetProfileVersion(hProfile, 4.3);
 
     if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error;
 
@@ -960,6 +960,11 @@
     // Colorant count now depends on the output space
     nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut);
 
+    // Make sure we have proper formatters
+    cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX,
+        FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace))
+        | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace)));
+
     // Apply the transfor to colorants.
     for (i=0; i < nColors; i++) {
         cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1);
@@ -980,6 +985,7 @@
 
 typedef struct {
     cmsBool              IsV4;             // Is a V4 tag?
+    cmsTagSignature      RequiredTag;      // Set to 0 for both types
     cmsTagTypeSignature  LutType;          // The LUT type
     int                  nTypes;           // Number of types (up to 5)
     cmsStageSignature    MpeTypes[5];      // 5 is the maximum number
@@ -988,16 +994,16 @@
 
 static const cmsAllowedLUT AllowedLUTTypes[] = {
 
-    { FALSE, cmsSigLut16Type,    4,  { cmsSigMatrixElemType,  cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
-    { FALSE, cmsSigLut16Type,    3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
-    { TRUE , cmsSigLutAtoBType,  1,  { cmsSigCurveSetElemType } },
-    { TRUE , cmsSigLutAtoBType,  3,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } },
-    { TRUE , cmsSigLutAtoBType,  3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType   } },
-    { TRUE , cmsSigLutAtoBType,  5,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
-    { TRUE , cmsSigLutBtoAType,  1,  { cmsSigCurveSetElemType }},
-    { TRUE , cmsSigLutBtoAType,  3,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
-    { TRUE , cmsSigLutBtoAType,  3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }},
-    { TRUE , cmsSigLutBtoAType,  5,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}
+    { FALSE, 0,              cmsSigLut16Type,    4,  { cmsSigMatrixElemType,  cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
+    { FALSE, 0,              cmsSigLut16Type,    3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
+    { TRUE , 0,              cmsSigLutAtoBType,  1,  { cmsSigCurveSetElemType }},
+    { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType,  3,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } },
+    { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType,  3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType   } },
+    { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType,  5,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
+    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  1,  { cmsSigCurveSetElemType }},
+    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  3,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
+    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }},
+    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  5,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}
 };
 
 #define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT))
@@ -1020,15 +1026,17 @@
 
 
 static
-const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4)
+const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag)
 {
-    int n;
+    cmsUInt32Number n;
 
     for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) {
 
         const cmsAllowedLUT* Tab = AllowedLUTTypes + n;
 
         if (IsV4 ^ Tab -> IsV4) continue;
+        if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue;
+
         if (CheckOne(Tab, Lut)) return Tab;
     }
 
@@ -1047,6 +1055,7 @@
     cmsStage* mpe;
     cmsContext ContextID = cmsGetTransformContextID(hTransform);
     const cmsAllowedLUT* AllowedLUT;
+    cmsTagSignature DestinationTag;
 
     _cmsAssert(hTransform != NULL);
 
@@ -1077,6 +1086,14 @@
         cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID));
     }
 
+
+    hProfile = cmsCreateProfilePlaceholder(ContextID);
+    if (!hProfile) goto Error;                    // can't allocate
+
+    cmsSetProfileVersion(hProfile, Version);
+
+    FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags);
+
     // Optimize the LUT and precalculate a devicelink
 
     ChansIn  = cmsChannelsOf(xform -> EntryColorSpace);
@@ -1089,17 +1106,22 @@
     FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2);
 
 
+     if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass)
+         DestinationTag = cmsSigBToA0Tag;
+     else
+         DestinationTag = cmsSigAToB0Tag;
+
     // Check if the profile/version can store the result
     if (dwFlags & cmsFLAGS_FORCE_CLUT)
         AllowedLUT = NULL;
     else
-    AllowedLUT = FindCombination(LUT, Version >= 4.0);
+        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
 
     if (AllowedLUT == NULL) {
 
         // Try to optimize
         _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
-        AllowedLUT = FindCombination(LUT, Version >= 4.0);
+        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
 
     }
 
@@ -1110,13 +1132,13 @@
         _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
 
         // Put identity curves if needed
-        if (cmsPipelineStageCount(LUT) == 1) {
+        if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)
+             cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn));
 
-            cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn));
-            cmsPipelineInsertStage(LUT, cmsAT_END,   _cmsStageAllocIdentityCurves(ContextID, ChansOut));
-        }
+        if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType)
+             cmsPipelineInsertStage(LUT, cmsAT_END,   _cmsStageAllocIdentityCurves(ContextID, ChansOut));
 
-        AllowedLUT = FindCombination(LUT, Version >= 4.0);
+        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
     }
 
     // Somethings is wrong...
@@ -1124,25 +1146,15 @@
         goto Error;
     }
 
-    hProfile = cmsCreateProfilePlaceholder(ContextID);
-    if (!hProfile) goto Error;                    // can't allocate
-
-    cmsSetProfileVersion(hProfile, Version);
-
-    FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags);
 
     if (dwFlags & cmsFLAGS_8BITS_DEVICELINK)
                      cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE);
 
     // Tag profile with information
-    if (!SetTextTags(hProfile, L"devicelink")) return NULL;
-
-    if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) {
+    if (!SetTextTags(hProfile, L"devicelink")) goto Error;
 
-        if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, LUT)) goto Error;
-    }
-    else
-        if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
+    // Store result
+    if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error;
 
 
     if (xform -> InputColorant != NULL) {
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c	2013-12-19 12:21:25.983481789 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c	2013-12-19 12:23:00.744901214 +0000
@@ -172,7 +172,7 @@
 // Robertson's method
 cmsBool  CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint)
 {
-    int j;
+    cmsUInt32Number j;
     cmsFloat64Number us,vs;
     cmsFloat64Number uj,vj,tj,di,dj,mi,mj;
     cmsFloat64Number xs, ys;
@@ -263,10 +263,10 @@
 cmsBool  _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll)
 {
     cmsMAT3 LamRigg   = {{ // Bradford matrix
-            {{  0.8951,  0.2664, -0.1614 }},
-            {{ -0.7502,  1.7135,  0.0367 }},
-            {{  0.0389, -0.0685,  1.0296 }}
-        }};
+        {{  0.8951,  0.2664, -0.1614 }},
+        {{ -0.7502,  1.7135,  0.0367 }},
+        {{  0.0389, -0.0685,  1.0296 }}
+      }};
 
     if (ConeMatrix == NULL)
         ConeMatrix = &LamRigg;
@@ -376,3 +376,5 @@
 
     return TRUE;
 }
+
+
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c	2013-12-19 12:21:25.987481850 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c	2013-12-19 12:24:35.462319107 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -60,8 +60,8 @@
 
 // Alarm codes for 16-bit transformations, because the fixed range of containers there are
 // no values left to mark out of gamut. volatile is C99 per 6.2.5
-static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS];
-static volatile cmsFloat64Number GlobalAdaptationState = 0;
+static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static volatile cmsFloat64Number GlobalAdaptationState = 1;
 
 // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
 cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
@@ -118,11 +118,13 @@
     if (p ->Sequence)
         cmsFreeProfileSequenceDescription(p ->Sequence);
 
-    LCMS_FREE_LOCK(&p->rwlock);
+    if (p ->UserData)
+        p ->FreeUserData(p ->ContextID, p ->UserData);
+
     _cmsFree(p ->ContextID, (void *) p);
 }
 
-// Apply transform
+// Apply transform.
 void CMSEXPORT cmsDoTransform(cmsHTRANSFORM  Transform,
                               const void* InputBuffer,
                               void* OutputBuffer,
@@ -131,7 +133,20 @@
 {
     _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
 
-    p -> xform(p, InputBuffer, OutputBuffer, Size);
+    p -> xform(p, InputBuffer, OutputBuffer, Size, Size);
+}
+
+
+// Apply transform.
+void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM  Transform,
+                              const void* InputBuffer,
+                              void* OutputBuffer,
+                              cmsUInt32Number Size, cmsUInt32Number Stride)
+
+{
+    _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
+
+    p -> xform(p, InputBuffer, OutputBuffer, Size, Stride);
 }
 
 
@@ -142,7 +157,7 @@
 static
 void FloatXFORM(_cmsTRANSFORM* p,
                 const void* in,
-                void* out, cmsUInt32Number Size)
+                void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
 {
     cmsUInt8Number* accum;
     cmsUInt8Number* output;
@@ -155,7 +170,7 @@
 
     for (i=0; i < Size; i++) {
 
-        accum = p -> FromInputFloat(p, fIn, accum, Size);
+        accum = p -> FromInputFloat(p, fIn, accum, Stride);
 
         // Any gamut chack to do?
         if (p ->GamutCheck != NULL) {
@@ -183,7 +198,7 @@
         }
 
         // Back to asked representation
-        output = p -> ToOutputFloat(p, fOut, output, Size);
+        output = p -> ToOutputFloat(p, fOut, output, Stride);
     }
 }
 
@@ -193,7 +208,8 @@
 static
 void NullXFORM(_cmsTRANSFORM* p,
                const void* in,
-               void* out, cmsUInt32Number Size)
+               void* out, cmsUInt32Number Size,
+               cmsUInt32Number Stride)
 {
     cmsUInt8Number* accum;
     cmsUInt8Number* output;
@@ -206,8 +222,8 @@
 
     for (i=0; i < n; i++) {
 
-        accum  = p -> FromInput(p, wIn, accum, Size);
-        output = p -> ToOutput(p, wIn, output, Size);
+        accum  = p -> FromInput(p, wIn, accum, Stride);
+        output = p -> ToOutput(p, wIn, output, Stride);
     }
 }
 
@@ -216,7 +232,7 @@
 static
 void PrecalculatedXFORM(_cmsTRANSFORM* p,
                         const void* in,
-                        void* out, cmsUInt32Number Size)
+                        void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
 {
     register cmsUInt8Number* accum;
     register cmsUInt8Number* output;
@@ -229,9 +245,9 @@
 
     for (i=0; i < n; i++) {
 
-        accum = p -> FromInput(p, wIn, accum, Size);
+        accum = p -> FromInput(p, wIn, accum, Stride);
         p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
-        output = p -> ToOutput(p, wOut, output, Size);
+        output = p -> ToOutput(p, wOut, output, Stride);
     }
 }
 
@@ -260,7 +276,7 @@
 static
 void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
                                   const void* in,
-                                  void* out, cmsUInt32Number Size)
+                                  void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
 {
     cmsUInt8Number* accum;
     cmsUInt8Number* output;
@@ -273,9 +289,9 @@
 
     for (i=0; i < n; i++) {
 
-        accum = p -> FromInput(p, wIn, accum, Size);
+        accum = p -> FromInput(p, wIn, accum, Stride);
         TransformOnePixelWithGamutCheck(p, wIn, wOut);
-        output = p -> ToOutput(p, wOut, output, Size);
+        output = p -> ToOutput(p, wOut, output, Stride);
     }
 }
 
@@ -284,13 +300,13 @@
 static
 void CachedXFORM(_cmsTRANSFORM* p,
                  const void* in,
-                 void* out, cmsUInt32Number Size)
+                 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
 {
     cmsUInt8Number* accum;
     cmsUInt8Number* output;
     cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
     cmsUInt32Number i, n;
-    cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS];
+    _cmsCACHE Cache;
 
     accum  = (cmsUInt8Number*)  in;
     output = (cmsUInt8Number*)  out;
@@ -300,36 +316,28 @@
     memset(wIn,  0, sizeof(wIn));
     memset(wOut, 0, sizeof(wOut));
 
-
-    LCMS_READ_LOCK(&p ->rwlock);
-    memmove(CacheIn,  p ->CacheIn, sizeof(CacheIn));
-    memmove(CacheOut, p ->CacheOut, sizeof(CacheOut));
-    LCMS_UNLOCK(&p ->rwlock);
+    // Get copy of zero cache
+    memcpy(&Cache, &p ->Cache, sizeof(Cache));
 
     for (i=0; i < n; i++) {
 
-        accum = p -> FromInput(p, wIn, accum, Size);
+        accum = p -> FromInput(p, wIn, accum, Stride);
 
-        if (memcmp(wIn, CacheIn, sizeof(CacheIn)) == 0) {
+        if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
 
-            memmove(wOut, CacheOut, sizeof(CacheOut));
+            memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
         }
         else {
 
             p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
 
-            memmove(CacheIn,  wIn,  sizeof(CacheIn));
-            memmove(CacheOut, wOut, sizeof(CacheOut));
+            memcpy(Cache.CacheIn,  wIn,  sizeof(Cache.CacheIn));
+            memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
         }
 
-        output = p -> ToOutput(p, wOut, output, Size);
+        output = p -> ToOutput(p, wOut, output, Stride);
     }
 
-
-    LCMS_WRITE_LOCK(&p ->rwlock);
-    memmove(p->CacheIn,  CacheIn, sizeof(CacheIn));
-    memmove(p->CacheOut, CacheOut, sizeof(CacheOut));
-    LCMS_UNLOCK(&p ->rwlock);
 }
 
 
@@ -337,13 +345,13 @@
 static
 void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
                            const void* in,
-                           void* out, cmsUInt32Number Size)
+                           void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
 {
        cmsUInt8Number* accum;
        cmsUInt8Number* output;
        cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
        cmsUInt32Number i, n;
-       cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS];
+       _cmsCACHE Cache;
 
        accum  = (cmsUInt8Number*)  in;
        output = (cmsUInt8Number*)  out;
@@ -353,51 +361,158 @@
        memset(wIn,  0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
        memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
 
-       LCMS_READ_LOCK(&p ->rwlock);
-           memmove(CacheIn,  p ->CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
-           memmove(CacheOut, p ->CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
-       LCMS_UNLOCK(&p ->rwlock);
-
+       // Get copy of zero cache
+       memcpy(&Cache, &p ->Cache, sizeof(Cache));
 
        for (i=0; i < n; i++) {
 
-            accum = p -> FromInput(p, wIn, accum, Size);
+            accum = p -> FromInput(p, wIn, accum, Stride);
 
-            if (memcmp(wIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS) == 0) {
-                    memmove(wOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+            if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
+                    memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
             }
             else {
                     TransformOnePixelWithGamutCheck(p, wIn, wOut);
-                    memmove(CacheIn, wIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
-                    memmove(CacheOut, wOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+                    memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
+                    memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
             }
 
-            output = p -> ToOutput(p, wOut, output, Size);
+            output = p -> ToOutput(p, wOut, output, Stride);
        }
 
-        LCMS_WRITE_LOCK(&p ->rwlock);
-           memmove(p->CacheIn,  CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
-           memmove(p->CacheOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
-        LCMS_UNLOCK(&p ->rwlock);
+}
+
+// -------------------------------------------------------------------------------------------------------------
+
+// List of used-defined transform factories
+typedef struct _cmsTransformCollection_st {
+
+    _cmsTransformFactory  Factory;
+    struct _cmsTransformCollection_st *Next;
+
+} _cmsTransformCollection;
+
+// The linked list head
+static _cmsTransformCollection* TransformCollection = NULL;
+
+// Register new ways to transform
+cmsBool  _cmsRegisterTransformPlugin(cmsPluginBase* Data)
+{
+    cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
+    _cmsTransformCollection* fl;
+
+      if (Data == NULL) {
+
+        // Free the chain. Memory is safely freed at exit
+        TransformCollection = NULL;
+        return TRUE;
+    }
+
+    // Factory callback is required
+   if (Plugin ->Factory == NULL) return FALSE;
+
+
+    fl = (_cmsTransformCollection*) _cmsPluginMalloc(sizeof(_cmsTransformCollection));
+    if (fl == NULL) return FALSE;
+
+      // Copy the parameters
+    fl ->Factory = Plugin ->Factory;
+
+    // Keep linked list
+    fl ->Next = TransformCollection;
+    TransformCollection = fl;
+
+    // All is ok
+    return TRUE;
 }
 
 
+void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
+{
+    _cmsAssert(CMMcargo != NULL);
+    CMMcargo ->UserData = ptr;
+    CMMcargo ->FreeUserData = FreePrivateDataFn;
+}
+
+// returns the pointer defined by the plug-in to store private data
+void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
+{
+    _cmsAssert(CMMcargo != NULL);
+    return CMMcargo ->UserData;
+}
 
+// returns the current formatters
+void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput)
+{
+     _cmsAssert(CMMcargo != NULL);
+     if (FromInput) *FromInput = CMMcargo ->FromInput;
+     if (ToOutput)  *ToOutput  = CMMcargo ->ToOutput;
+}
 
-// Allocate transform struct and set it to defaults
+void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)
+{
+     _cmsAssert(CMMcargo != NULL);
+     if (FromInput) *FromInput = CMMcargo ->FromInputFloat;
+     if (ToOutput)  *ToOutput  = CMMcargo ->ToOutputFloat;
+}
+
+
+// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
+// for separated transforms. If this is the case,
 static
-_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags)
+_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
+                                               cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
 {
+     _cmsTransformCollection* Plugin;
+
     // Allocate needed memory
     _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
     if (!p) return NULL;
 
+    // Store the proposed pipeline
+    p ->Lut = lut;
+
+    // Let's see if any plug-in want to do the transform by itself
+    for (Plugin = TransformCollection;
+        Plugin != NULL;
+        Plugin = Plugin ->Next) {
+
+            if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) {
+
+                // Last plugin in the declaration order takes control. We just keep
+                // the original parameters as a logging.
+                // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
+                // an optimized transform is not reusable. The plug-in can, however, change
+                // the flags and make it suitable.
+
+                p ->ContextID       = ContextID;
+                p ->InputFormat     = *InputFormat;
+                p ->OutputFormat    = *OutputFormat;
+                p ->dwOriginalFlags = *dwFlags;
+
+                // Fill the formatters just in case the optimized routine is interested.
+                // No error is thrown if the formatter doesn't exist. It is up to the optimization
+                // factory to decide what to do in those cases.
+                p ->FromInput      = _cmsGetFormatter(*InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+                p ->ToOutput       = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+                p ->FromInputFloat = _cmsGetFormatter(*InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+                p ->ToOutputFloat  = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+
+                return p;
+            }
+    }
+
+    // Not suitable for the transform plug-in, let's check  the pipeline plug-in
+    if (p ->Lut != NULL)
+        _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
+
     // Check whatever this is a true floating point transform
-    if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) {
+    if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
 
         // Get formatter function always return a valid union, but the contents of this union may be NULL.
-        p ->FromInputFloat = _cmsGetFormatter(InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
-        p ->ToOutputFloat  = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+        p ->FromInputFloat = _cmsGetFormatter(*InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+        p ->ToOutputFloat  = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+        *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
 
         if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
 
@@ -411,31 +526,45 @@
     }
     else {
 
-        p ->FromInput = _cmsGetFormatter(InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
-        p ->ToOutput  = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+        if (*InputFormat == 0 && *OutputFormat == 0) {
+            p ->FromInput = p ->ToOutput = NULL;
+            *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+        }
+        else {
 
-        if (p ->FromInput == NULL || p ->ToOutput == NULL) {
+            int BytesPerPixelInput;
  
-            cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
-            _cmsFree(ContextID, p);
-            return NULL;
+            p ->FromInput = _cmsGetFormatter(*InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+            p ->ToOutput  = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+
+            if (p ->FromInput == NULL || p ->ToOutput == NULL) {
+
+                cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
+                _cmsFree(ContextID, p);
+                return NULL;
+            }
+
+            BytesPerPixelInput = T_BYTES(p ->InputFormat);
+            if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
+                   *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+
         }
 
-        if (dwFlags & cmsFLAGS_NULLTRANSFORM) {
+        if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
 
             p ->xform = NullXFORM;
         }
         else {
-            if (dwFlags & cmsFLAGS_NOCACHE) {
-
-                if (dwFlags & cmsFLAGS_GAMUTCHECK)
+            if (*dwFlags & cmsFLAGS_NOCACHE) {
+ 
+                if (*dwFlags & cmsFLAGS_GAMUTCHECK)
                     p ->xform = PrecalculatedXFORMGamutCheck;  // Gamut check, no cachÃ©
                 else
                     p ->xform = PrecalculatedXFORM;  // No cachÃ©, no gamut check
             }
             else {
 
-                if (dwFlags & cmsFLAGS_GAMUTCHECK)
+                if (*dwFlags & cmsFLAGS_GAMUTCHECK)
                     p ->xform = CachedXFORMGamutCheck;    // Gamut check, cachÃ©
                 else
                     p ->xform = CachedXFORM;  // No gamut check, cachÃ©
@@ -444,14 +573,11 @@
         }
     }
 
-
-    // Create a mutex for shared memory
-    LCMS_CREATE_LOCK(&p->rwlock);
-
-    p ->InputFormat     = InputFormat;
-    p ->OutputFormat    = OutputFormat;
-    p ->dwOriginalFlags = dwFlags;
+    p ->InputFormat     = *InputFormat;
+    p ->OutputFormat    = *OutputFormat;
+    p ->dwOriginalFlags = *dwFlags;
     p ->ContextID       = ContextID;
+    p ->UserData        = NULL;
     return p;
 }
 
@@ -462,12 +588,14 @@
     cmsColorSpaceSignature PostColorSpace;
     int i;
 
+    if (nProfiles <= 0) return FALSE;
     if (hProfiles[0] == NULL) return FALSE;
 
     *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
 
     for (i=0; i < nProfiles; i++) {
 
+        cmsProfileClassSignature cls;
         cmsHPROFILE hProfile = hProfiles[i];
 
         int lIsInput = (PostColorSpace != cmsSigXYZData) &&
@@ -475,17 +603,28 @@
 
         if (hProfile == NULL) return FALSE;
 
-        if (lIsInput) {
+        cls = cmsGetDeviceClass(hProfile);
+
+        if (cls == cmsSigNamedColorClass) {
+
+            ColorSpaceIn    = cmsSig1colorData;
+            ColorSpaceOut   = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
+        }
+        else
+        if (lIsInput || (cls == cmsSigLinkClass)) {
 
             ColorSpaceIn    = cmsGetColorSpace(hProfile);
             ColorSpaceOut   = cmsGetPCS(hProfile);
         }
-        else {
-
+        else
+        {
             ColorSpaceIn    = cmsGetPCS(hProfile);
             ColorSpaceOut   = cmsGetColorSpace(hProfile);
         }
 
+        if (i==0)
+            *Input = ColorSpaceIn;
+
         PostColorSpace = ColorSpaceOut;
     }
 
@@ -531,6 +670,12 @@
     cmsPipeline* Lut;
     cmsUInt32Number LastIntent = Intents[nProfiles-1];
 
+    // If it is a fake transform
+    if (dwFlags & cmsFLAGS_NULLTRANSFORM)
+    {
+        return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
+    }
+
     // If gamut check is requested, make sure we have a gamut profile
     if (dwFlags & cmsFLAGS_GAMUTCHECK) {
         if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
@@ -566,21 +711,24 @@
         return NULL;
     }
 
-    // Optimize the LUT if possible
-    _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
+    // Check channel count
+    if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
+        (cmsChannelsOf(ExitColorSpace)  != cmsPipelineOutputChannels(Lut))) {
+        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
+        return NULL;
+    }
 
 
     // All seems ok
-    xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
+    xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
     if (xform == NULL) {
-        cmsPipelineFree(Lut);
         return NULL;
     }
 
     // Keep values
     xform ->EntryColorSpace = EntryColorSpace;
     xform ->ExitColorSpace  = ExitColorSpace;
-    xform ->Lut             = Lut;
+    xform ->RenderingIntent = Intents[nProfiles-1];
 
 
     // Create a gamut check LUT if requested
@@ -627,14 +775,14 @@
     // If this is a cached transform, init first value, which is zero (16 bits only)
     if (!(dwFlags & cmsFLAGS_NOCACHE)) {
 
-        memset(&xform ->CacheIn, 0, sizeof(xform ->CacheIn));
+        memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
 
         if (xform ->GamutCheck != NULL) {
-            TransformOnePixelWithGamutCheck(xform, xform ->CacheIn, xform->CacheOut);
+            TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
         }
         else {
 
-            xform ->Lut ->Eval16Fn(xform ->CacheIn, xform->CacheOut, xform -> Lut->Data);
+            xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
         }
 
     }
@@ -643,7 +791,6 @@
 }
 
 // Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
-
 cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
                                                        cmsHPROFILE hProfiles[],
                                                        cmsUInt32Number nProfiles,
@@ -785,3 +932,53 @@
     if (xform == NULL) return NULL;
     return xform -> ContextID;
 }
+
+// Grab the input/output formats
+cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
+{
+    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
+
+    if (xform == NULL) return 0;
+    return xform->InputFormat;
+}
+
+cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
+{
+    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
+
+    if (xform == NULL) return 0;
+    return xform->OutputFormat;
+}
+
+// For backwards compatibility
+cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
+                                         cmsUInt32Number InputFormat,
+                                         cmsUInt32Number OutputFormat)
+{
+
+    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
+    cmsFormatter16 FromInput, ToOutput;
+
+
+    // We only can afford to change formatters if previous transform is at least 16 bits
+    if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
+
+        cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
+        return FALSE;
+    }
+
+    FromInput = _cmsGetFormatter(InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+    ToOutput  = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+
+    if (FromInput == NULL || ToOutput == NULL) {
+
+        cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
+        return FALSE;
+    }
+
+    xform ->InputFormat  = InputFormat;
+    xform ->OutputFormat = OutputFormat;
+    xform ->FromInput    = FromInput;
+    xform ->ToOutput     = ToOutput;
+    return TRUE;
+}
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h	2013-12-19 12:21:25.987481850 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -52,7 +52,7 @@
 //
 //---------------------------------------------------------------------------------
 //
-// Version 2.0
+// Version 2.4
 //
 
 #ifndef _lcms2_H
@@ -69,9 +69,6 @@
 // Uncomment this if your compiler doesn't work with fast floor function
 // #define CMS_DONT_USE_FAST_FLOOR 1
 
-// Uncomment this line if your system does not support multithreading
-#define CMS_DONT_USE_PTHREADS    1
-
 // Uncomment this line if you want lcms to use the black point tag in profile,
 // if commented, lcms will compute the black point by its own.
 // It is safer to leave it commented out
@@ -84,6 +81,9 @@
 // require "KEYWORD" on undefined identifiers, keep it comented out unless needed
 // #define CMS_STRICT_CGATS  1
 
+// Uncomment to get rid of the tables for "half" float support
+// #define CMS_NO_HALF_SUPPORT 1
+
 // ********** End of configuration toggles ******************************
 
 // Needed for streams
@@ -101,7 +101,7 @@
 #endif
 
 // Version/release
-#define LCMS_VERSION        2000
+#define LCMS_VERSION        2040
 
 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant
 #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -110,6 +110,10 @@
 typedef unsigned char        cmsUInt8Number;   // That is guaranteed by the C99 spec
 typedef signed char          cmsInt8Number;    // That is guaranteed by the C99 spec
 
+#if CHAR_BIT != 8
+#  error "Unable to find 8 bit type, unsupported compiler"
+#endif
+
 // IEEE float storage numbers
 typedef float                cmsFloat32Number;
 typedef double               cmsFloat64Number;
@@ -211,11 +215,13 @@
 #endif
 
 #ifdef TARGET_CPU_PPC
+# if TARGET_CPU_PPC
 #   define CMS_USE_BIG_ENDIAN   1
+# endif
 #endif
 
 #ifdef macintosh
-# ifndef __LITTLE_ENDIAN__
+# ifdef __BIG_ENDIAN__
 #   define CMS_USE_BIG_ENDIAN      1
 # endif
 #endif
@@ -276,6 +282,7 @@
     cmsSigCrdInfoType                       = 0x63726469,  // 'crdi'
     cmsSigCurveType                         = 0x63757276,  // 'curv'
     cmsSigDataType                          = 0x64617461,  // 'data'
+    cmsSigDictType                          = 0x64696374,  // 'dict'
     cmsSigDateTimeType                      = 0x6474696D,  // 'dtim'
     cmsSigDeviceSettingsType                = 0x64657673,  // 'devs'
     cmsSigLut16Type                         = 0x6d667432,  // 'mft2'
@@ -302,9 +309,10 @@
     cmsSigUInt32ArrayType                   = 0x75693332,  // 'ui32'
     cmsSigUInt64ArrayType                   = 0x75693634,  // 'ui64'
     cmsSigUInt8ArrayType                    = 0x75693038,  // 'ui08'
+    cmsSigVcgtType                          = 0x76636774,  // 'vcgt'
     cmsSigViewingConditionsType             = 0x76696577,  // 'view'
-    cmsSigXYZType                           = 0x58595A20,  // 'XYZ '
-    cmsSigVcgtType                          = 0x76636774   // 'vcgt'
+    cmsSigXYZType                           = 0x58595A20   // 'XYZ '
+
 
 } cmsTagTypeSignature;
 
@@ -377,7 +385,8 @@
     cmsSigUcrBgTag                          = 0x62666420,  // 'bfd '
     cmsSigViewingCondDescTag                = 0x76756564,  // 'vued'
     cmsSigViewingConditionsTag              = 0x76696577,  // 'view'
-    cmsSigVcgtTag                           = 0x76636774   // 'vcgt'
+    cmsSigVcgtTag                           = 0x76636774,  // 'vcgt'
+    cmsSigMetaTag                           = 0x6D657461   // 'meta'
 
 } cmsTagSignature;
 
@@ -409,7 +418,7 @@
     cmsSigMotionPictureFilmScanner          = 0x6D706673,  // 'mpfs'
     cmsSigMotionPictureFilmRecorder         = 0x6D706672,  // 'mpfr'
     cmsSigDigitalMotionPictureCamera        = 0x646D7063,  // 'dmpc'
-    cmsSigDigitalCinemaProjector            = 0x64636A70,  // 'dcpj'
+    cmsSigDigitalCinemaProjector            = 0x64636A70   // 'dcpj'
 
 } cmsTechnologySignature;
 
@@ -436,12 +445,12 @@
     cmsSigMCH7Data                          = 0x4D434837,  // 'MCH7'
     cmsSigMCH8Data                          = 0x4D434838,  // 'MCH8'
     cmsSigMCH9Data                          = 0x4D434839,  // 'MCH9'
-    cmsSigMCHAData                          = 0x4D43483A,  // 'MCHA'
-    cmsSigMCHBData                          = 0x4D43483B,  // 'MCHB'
-    cmsSigMCHCData                          = 0x4D43483C,  // 'MCHC'
-    cmsSigMCHDData                          = 0x4D43483D,  // 'MCHD'
-    cmsSigMCHEData                          = 0x4D43483E,  // 'MCHE'
-    cmsSigMCHFData                          = 0x4D43483F,  // 'MCHF'
+    cmsSigMCHAData                          = 0x4D434841,  // 'MCHA'
+    cmsSigMCHBData                          = 0x4D434842,  // 'MCHB'
+    cmsSigMCHCData                          = 0x4D434843,  // 'MCHC'
+    cmsSigMCHDData                          = 0x4D434844,  // 'MCHD'
+    cmsSigMCHEData                          = 0x4D434845,  // 'MCHE'
+    cmsSigMCHFData                          = 0x4D434846,  // 'MCHF'
     cmsSigNamedData                         = 0x6e6d636c,  // 'nmcl'
     cmsSig1colorData                        = 0x31434C52,  // '1CLR'
     cmsSig2colorData                        = 0x32434C52,  // '2CLR'
@@ -470,7 +479,7 @@
     cmsSigLinkClass                         = 0x6C696E6B,  // 'link'
     cmsSigAbstractClass                     = 0x61627374,  // 'abst'
     cmsSigColorSpaceClass                   = 0x73706163,  // 'spac'
-    cmsSigNamedColorClass                   = 0x6e6d636c,  // 'nmcl'
+    cmsSigNamedColorClass                   = 0x6e6d636c   // 'nmcl'
 
 } cmsProfileClassSignature;
 
@@ -512,7 +521,13 @@
     cmsSigLabV4toV2                     = 0x34203220,  // '4 2 '
 
     // Identities
-    cmsSigIdentityElemType              = 0x69646E20   // 'idn '
+    cmsSigIdentityElemType              = 0x69646E20,  // 'idn '
+
+    // Float to floatPCS
+    cmsSigLab2FloatPCS                  = 0x64326C20,  // 'd2l '
+    cmsSigFloatPCS2Lab                  = 0x6C326420,  // 'l2d '
+    cmsSigXYZ2FloatPCS                  = 0x64327820,  // 'd2x '
+    cmsSigFloatPCS2XYZ                  = 0x78326420   // 'x2d '
 
 } cmsStageSignature;
 
@@ -635,7 +650,9 @@
 
 // Format of pixel is defined by one cmsUInt32Number, using bit fields as follows
 //
-//            A O TTTTT U Y F P X S EEE CCCC BBB
+//                               2                1          0
+//                          3 2 10987 6 5 4 3 2 1 098 7654 321
+//                          A O TTTTT U Y F P X S EEE CCCC BBB
 //
 //            A: Floating point -- With this flag we can differentiate 16 bits as float and as int
 //            O: Optimized -- previous optimization already returns the final 8-bit value
@@ -743,16 +760,19 @@
 #define TYPE_RGBA_16_SE        (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
 
 #define TYPE_ARGB_8            (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ARGB_8_PLANAR     (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
 #define TYPE_ARGB_16           (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
 
 #define TYPE_ABGR_8            (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_ABGR_8_PLANAR     (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1))
 #define TYPE_ABGR_16           (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
 #define TYPE_ABGR_16_PLANAR    (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
 #define TYPE_ABGR_16_SE        (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
 
 #define TYPE_BGRA_8            (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_8_PLANAR     (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
 #define TYPE_BGRA_16           (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_BGRA_16_SE        (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_16_SE        (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
 
 #define TYPE_CMY_8             (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1))
 #define TYPE_CMY_8_PLANAR      (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
@@ -834,8 +854,8 @@
 #define TYPE_Lab_8             (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1))
 #define TYPE_LabV2_8           (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1))
 
-#define TYPE_ALab_8            (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1))
-#define TYPE_ALabV2_8          (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1))
+#define TYPE_ALab_8            (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ALabV2_8          (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1))
 #define TYPE_Lab_16            (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2))
 #define TYPE_LabV2_16          (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(2))
 #define TYPE_Yxy_16            (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2))
@@ -874,8 +894,16 @@
 // Float formatters.
 #define TYPE_XYZ_FLT          (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4))
 #define TYPE_Lab_FLT          (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4))
+#define TYPE_LabA_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
 #define TYPE_GRAY_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4))
 #define TYPE_RGB_FLT          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4))
+
+#define TYPE_RGBA_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
+#define TYPE_ARGB_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1))
+#define TYPE_BGR_FLT          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1))
+#define TYPE_BGRA_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ABGR_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1))
+
 #define TYPE_CMYK_FLT         (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4))
 
 // Floating point formatters.
@@ -884,8 +912,21 @@
 #define TYPE_Lab_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0))
 #define TYPE_GRAY_DBL         (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0))
 #define TYPE_RGB_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
+#define TYPE_BGR_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1))
 #define TYPE_CMYK_DBL         (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0))
 
+// IEEE 754-2008 "half"
+#define TYPE_GRAY_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2))
+#define TYPE_RGB_HALF_FLT     (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_RGBA_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_CMYK_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2))
+
+#define TYPE_RGBA_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_ARGB_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
+#define TYPE_BGR_HALF_FLT     (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_BGRA_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ABGR_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
+
 #endif
 
 // Colorspaces
@@ -1116,6 +1157,10 @@
 CMSAPI cmsInt32Number    CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t);
 CMSAPI cmsFloat64Number  CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision);
 
+// Tone curve tabular estimation
+CMSAPI cmsUInt32Number         CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t);
+CMSAPI const cmsUInt16Number*  CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t);
+
 
 // Implements pipelines of multi-processing elements -------------------------------------------------------------
 
@@ -1128,6 +1173,7 @@
 CMSAPI void              CMSEXPORT cmsPipelineFree(cmsPipeline* lut);
 CMSAPI cmsPipeline*      CMSEXPORT cmsPipelineDup(const cmsPipeline* Orig);
 
+CMSAPI cmsContext        CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut);
 CMSAPI cmsUInt32Number   CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut);
 CMSAPI cmsUInt32Number   CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut);
 
@@ -1188,10 +1234,9 @@
 #define SAMPLER_INSPECT     0x01000000
 
 // For CLUT only
-CMSAPI cmsBool           CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe,    cmsSAMPLER16 Sampler,    void* Cargo, cmsUInt32Number dwFlags);
+CMSAPI cmsBool           CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe,    cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags);
 CMSAPI cmsBool           CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags);
 
-
 // Slicers
 CMSAPI cmsBool           CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
                                                    cmsSAMPLER16 Sampler, void * Cargo);
@@ -1301,6 +1346,7 @@
 // Profile sequence descriptor. Some fields come from profile sequence descriptor tag, others
 // come from Profile Sequence Identifier Tag
 typedef struct {
+
     cmsSignature           deviceMfg;
     cmsSignature           deviceModel;
     cmsUInt64Number        attributes;
@@ -1324,6 +1370,27 @@
 CMSAPI cmsSEQ*           CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq);
 CMSAPI void              CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq);
 
+// Dictionaries --------------------------------------------------------------------------------------------------------
+
+typedef struct _cmsDICTentry_struct {
+
+    struct _cmsDICTentry_struct* Next;
+
+    cmsMLU *DisplayName;
+    cmsMLU *DisplayValue;
+    wchar_t* Name;
+    wchar_t* Value;
+
+} cmsDICTentry;
+
+CMSAPI cmsHANDLE           CMSEXPORT cmsDictAlloc(cmsContext ContextID);
+CMSAPI void                CMSEXPORT cmsDictFree(cmsHANDLE hDict);
+CMSAPI cmsHANDLE           CMSEXPORT cmsDictDup(cmsHANDLE hDict);
+
+CMSAPI cmsBool             CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue);
+CMSAPI const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict);
+CMSAPI const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e);
+
 // Access to Profile data ----------------------------------------------------------------------------------------------
 CMSAPI cmsHPROFILE       CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID);
 
@@ -1336,12 +1403,18 @@
 CMSAPI void*             CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig);
 CMSAPI cmsBool           CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data);
 CMSAPI cmsBool           CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest);
+CMSAPI cmsTagSignature   CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig);
 
 // Read and write raw data
 CMSAPI cmsInt32Number    CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize);
 CMSAPI cmsBool           CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size);
 
 // Access header data
+#define cmsEmbeddedProfileFalse    0x00000000
+#define cmsEmbeddedProfileTrue     0x00000001
+#define cmsUseAnywhere             0x00000000
+#define cmsUseWithEmbeddedDataOnly 0x00000002
+
 CMSAPI cmsUInt32Number   CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile);
 CMSAPI void              CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags);
 CMSAPI void              CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID);
@@ -1377,9 +1450,9 @@
 #define LCMS_USED_AS_OUTPUT     1
 #define LCMS_USED_AS_PROOF      2
 
-CMSAPI cmsBool           CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection);
+CMSAPI cmsBool           CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection);
 CMSAPI cmsBool           CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile);
-CMSAPI cmsBool           CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection);
+CMSAPI cmsBool           CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection);
 
 // Translate form/to our notation to ICC
 CMSAPI cmsColorSpaceSignature   CMSEXPORT _cmsICCcolorSpace(int OurNotation);
@@ -1528,7 +1601,6 @@
 #define cmsFLAGS_NOOPTIMIZE               0x0100    // Inhibit optimizations
 #define cmsFLAGS_NULLTRANSFORM            0x0200    // Don't transform anyway
 
-
 // Proofing flags
 #define cmsFLAGS_GAMUTCHECK               0x1000    // Out of Gamut alarm
 #define cmsFLAGS_SOFTPROOFING             0x4000    // Do softproofing
@@ -1626,14 +1698,32 @@
                                                  void * OutputBuffer,
                                                  cmsUInt32Number Size);
 
+CMSAPI void             CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
+                                                 const void * InputBuffer,
+                                                 void * OutputBuffer,
+                                                 cmsUInt32Number Size,
+                                                 cmsUInt32Number Stride);
+
+
 CMSAPI void             CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
 CMSAPI void             CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
 
 // Adaptation state for absolute colorimetric intent
 CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d);
 
+// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
 CMSAPI cmsContext       CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform);
 
+// Grab the input/output formats
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform);
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform);
+
+// For backwards compatibility
+CMSAPI cmsBool          CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
+                                                         cmsUInt32Number InputFormat,
+                                                         cmsUInt32Number OutputFormat);
+
+
 
 // PostScript ColorRenderingDictionary and ColorSpaceArray ----------------------------------------------------
 
@@ -1677,12 +1767,15 @@
 CMSAPI cmsBool          CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* cProp, const char *Str);
 CMSAPI cmsBool          CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val);
 CMSAPI cmsBool          CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val);
+CMSAPI cmsBool          CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer);
 CMSAPI cmsBool          CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer);
 
 
 CMSAPI const char*      CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* cProp);
 CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp);
+CMSAPI const char*      CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey);
 CMSAPI cmsUInt32Number  CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames);
+CMSAPI cmsUInt32Number  CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames);
 
 // Datasets
 CMSAPI const char*      CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col);
@@ -1712,10 +1805,13 @@
 CMSAPI int              CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames);
 
 CMSAPI const char*      CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer);
+CMSAPI int              CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch);
 
 // The LABEL extension
 CMSAPI int              CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType);
 
+CMSAPI cmsBool          CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample);
+
 // Formatter for double
 CMSAPI void             CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter);
 
@@ -1731,6 +1827,7 @@
 
 // Estimate the black point
 CMSAPI cmsBool          CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags);
+CMSAPI cmsBool          CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags);
 
 // Estimate total area coverage
 CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile);
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h	2013-12-19 12:21:25.991481911 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -75,16 +75,18 @@
 #       define M_LOG10E    0.434294481903251827651
 #endif
 
-// BorlandC 5.5 is broken on that
-#ifdef __BORLANDC__
+// BorlandC 5.5, VC2003 are broken on that
+#if defined(__BORLANDC__) || (_MSC_VER < 1400) // 1400 == VC++ 8.0
 #define sinf(x) (float)sin((float)x)
 #define sqrtf(x) (float)sqrt((float)x)
 #endif
 
 
 // Alignment of ICC file format uses 4 bytes (cmsUInt32Number)
-#define _cmsSIZEOFLONGMINUS1    (sizeof(cmsUInt32Number)-1)
-#define _cmsALIGNLONG(x) (((x)+_cmsSIZEOFLONGMINUS1) & ~(_cmsSIZEOFLONGMINUS1))
+#define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1))
+
+// Alignment to memory pointer
+#define _cmsALIGNMEM(x)  (((x)+(sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
 
 // Maximum encodeable values in floating point
 #define MAX_ENCODEABLE_XYZ  (1.0 + 32767.0/32768.0)
@@ -94,7 +96,7 @@
 #define MAX_ENCODEABLE_ab4  (127.0)
 
 // Maximum of channels for internal pipeline evaluation
-#define MAX_STAGE_CHANNELS      128
+#define MAX_STAGE_CHANNELS  128
 
 // Unused parameter warning supression
 #define cmsUNUSED_PARAMETER(x) ((void)x)
@@ -117,36 +119,6 @@
 # endif
 #endif
 
-// Pthreads. In windows we use the native WIN32 API instead
-#ifdef CMS_DONT_USE_PTHREADS
-typedef int LCMS_RWLOCK_T;
-#   define LCMS_CREATE_LOCK(x)
-#   define LCMS_FREE_LOCK(x)
-#   define LCMS_READ_LOCK(x)
-#   define LCMS_WRITE_LOCK(x)
-#   define LCMS_UNLOCK(x)
-#else
-#ifdef CMS_IS_WINDOWS_
-#   ifndef WIN32_LEAN_AND_MEAN
-#       define WIN32_LEAN_AND_MEAN
-#   endif
-#   include <windows.h>
-    typedef CRITICAL_SECTION LCMS_RWLOCK_T;
-#   define LCMS_CREATE_LOCK(x)       InitializeCriticalSection((x))
-#   define LCMS_FREE_LOCK(x)         DeleteCriticalSection((x))
-#   define LCMS_READ_LOCK(x)         EnterCriticalSection((x))
-#   define LCMS_WRITE_LOCK(x)        EnterCriticalSection((x))
-#   define LCMS_UNLOCK(x)            LeaveCriticalSection((x))
-#else
-#   include <pthread.h>
-    typedef    pthread_rwlock_t      LCMS_RWLOCK_T;
-#   define LCMS_CREATE_LOCK(x)       pthread_rwlock_init((x), NULL)
-#   define LCMS_FREE_LOCK(x)         pthread_rwlock_destroy((x))
-#   define LCMS_READ_LOCK(x)         pthread_rwlock_rdlock((x))
-#   define LCMS_WRITE_LOCK(x)        pthread_rwlock_wrlock((x))
-#   define LCMS_UNLOCK(x)            pthread_rwlock_unlock((x))
-#endif
-#endif
 
 // A fast way to convert from/to 16 <-> 8 bits
 #define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb))
@@ -253,6 +225,8 @@
 // Optimization
 cmsBool  _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin);
 
+// Transform
+cmsBool  _cmsRegisterTransformPlugin(cmsPluginBase* Plugin);
 
 // ---------------------------------------------------------------------------------------------------------
 
@@ -396,6 +370,7 @@
 cmsInterpParams*     _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
 cmsInterpParams*     _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
 void                 _cmsFreeInterpParams(cmsInterpParams* p);
+cmsBool              _cmsSetInterpolationRoutine(cmsInterpParams* p);
 
 // Curves ----------------------------------------------------------------------------------------------------------------
 
@@ -443,37 +418,6 @@
     struct _cmsStage_struct* Next;
 };
 
-// Data kept in "Element" member of cmsStage
-
-// Curves
-typedef struct {
-    cmsUInt32Number nCurves;
-    cmsToneCurve**  TheCurves;
-
-} _cmsStageToneCurvesData;
-
-// Matrix
-typedef struct {
-    cmsFloat64Number*  Double;          // floating point for the matrix
-    cmsFloat64Number*  Offset;          // The offset
-
-} _cmsStageMatrixData;
-
-// CLUT
-typedef struct {
-
-    union {                       // Can have only one of both representations at same time
-        cmsUInt16Number*  T;      // Points to the table 16 bits table
-        cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table
-
-    } Tab;
-
-    cmsInterpParams* Params;
-    cmsUInt32Number  nEntries;
-    cmsBool          HasFloatValues;
-
-} _cmsStageCLutData;
-
 
 // Special Stages (cannot be saved)
 cmsStage*        _cmsStageAllocLab2XYZ(cmsContext ContextID);
@@ -482,9 +426,13 @@
 cmsStage*        _cmsStageAllocLabV2ToV4(cmsContext ContextID);
 cmsStage*        _cmsStageAllocLabV2ToV4curves(cmsContext ContextID);
 cmsStage*        _cmsStageAllocLabV4ToV2(cmsContext ContextID);
-cmsStage*        _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList);
+cmsStage*        _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS);
 cmsStage*        _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels);
 cmsStage*        _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan);
+cmsStage*        _cmsStageNormalizeFromLabFloat(cmsContext ContextID);
+cmsStage*        _cmsStageNormalizeFromXyzFloat(cmsContext ContextID);
+cmsStage*        _cmsStageNormalizeToLabFloat(cmsContext ContextID);
+cmsStage*        _cmsStageNormalizeToXyzFloat(cmsContext ContextID);
 
 // For curve set only
 cmsToneCurve**     _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
@@ -505,12 +453,12 @@
 
    _cmsOPTeval16Fn         Eval16Fn;
    _cmsPipelineEvalFloatFn EvalFloatFn;
-   _cmsOPTfreeDataFn       FreeDataFn;
-   _cmsOPTdupDataFn        DupDataFn;
+   _cmsFreeUserDataFn      FreeDataFn;
+   _cmsDupUserDataFn       DupDataFn;
 
     cmsContext ContextID;            // Environment
 
-    cmsBool  SaveAs8Bits;            // Implemntation-specific: save as 8 bits if possible
+    cmsBool  SaveAs8Bits;            // Implementation-specific: save as 8 bits if possible
 };
 
 // LUT reading & creation -------------------------------------------------------------------------------------------
@@ -573,6 +521,8 @@
 
 // Formatters ------------------------------------------------------------------------------------------------------------
 
+#define cmsFLAGS_CAN_CHANGE_FORMATTER     0x02000000   // Allow change buffer format
+
 cmsBool         _cmsFormatterIsFloat(cmsUInt32Number Type);
 cmsBool         _cmsFormatterIs8bit(cmsUInt32Number Type);
 
@@ -581,21 +531,27 @@
                                  cmsUInt32Number dwFlags);
 
 
+#ifndef CMS_NO_HALF_SUPPORT
+
+// Half float
+cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h);
+cmsUInt16Number  _cmsFloat2Half(cmsFloat32Number flt);
+
+#endif
+
 // Transform logic ------------------------------------------------------------------------------------------------------
 
 struct _cmstransform_struct;
 
-// Full xform
-typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform,
-                                 const void* InputBuffer,
-                                 void* OutputBuffer, cmsUInt32Number Size);
-
 typedef struct {
 
-    cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
-    cmsUInt32Number StrideIn, StrideOut;       // Planar support
+    // 1-pixel cache (16 bits only)
+    cmsUInt16Number CacheIn[cmsMAXCHANNELS];
+    cmsUInt16Number CacheOut[cmsMAXCHANNELS];
+
+} _cmsCACHE;
+
 
-} cmsFormatterInfo;
 
 // Transformation
 typedef struct _cmstransform_struct {
@@ -612,17 +568,13 @@
     cmsFormatterFloat FromInputFloat;
     cmsFormatterFloat ToOutputFloat;
 
-    // 1-pixel cache (16 bits only)
-    cmsUInt16Number CacheIn[cmsMAXCHANNELS];
-    cmsUInt16Number CacheOut[cmsMAXCHANNELS];
-
-    // Semaphor for cache
-    LCMS_RWLOCK_T rwlock;
+    // 1-pixel cache seed for zero as input (16 bits, read only)
+    _cmsCACHE Cache;
 
-    // A MPE LUT holding the full (optimized) transform
+    // A Pipeline holding the full (optimized) transform
     cmsPipeline* Lut;
 
-    // A MPE LUT holding the gamut check. It goes from the input space to bilevel
+    // A Pipeline holding the gamut check. It goes from the input space to bilevel
     cmsPipeline* GamutCheck;
 
     // Colorant tables
@@ -645,6 +597,10 @@
     // An id that uniquely identifies the running context. May be null.
     cmsContext ContextID;
 
+    // A user-defined pointer that can be used to store data for transform plug-ins
+    void* UserData;
+    _cmsFreeUserDataFn FreeUserData;
+
 } _cmsTRANSFORM;
 
 // --------------------------------------------------------------------------------------------------
diff -Nru openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
--- openjdk.orig/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h	2013-12-19 12:21:25.991481911 +0000
+++ openjdk/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h	2013-12-19 12:23:00.748901273 +0000
@@ -30,7 +30,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2011 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"),
@@ -144,6 +144,7 @@
 
     cmsContext        ContextID;
     cmsUInt32Number   UsedSpace;
+    cmsUInt32Number   ReportedSize;
     char              PhysicalFile[cmsMAX_PATH];
 
     cmsUInt32Number   (* Read)(struct _cms_io_handler* iohandler, void *Buffer,
@@ -159,7 +160,7 @@
 // Endianess adjust functions
 CMSAPI cmsUInt16Number   CMSEXPORT  _cmsAdjustEndianess16(cmsUInt16Number Word);
 CMSAPI cmsUInt32Number   CMSEXPORT  _cmsAdjustEndianess32(cmsUInt32Number Value);
-CMSAPI void              CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord);
+CMSAPI void              CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord);
 
 // Helper IO functions
 CMSAPI cmsBool           CMSEXPORT  _cmsReadUInt8Number(cmsIOHANDLER* io,  cmsUInt8Number* n);
@@ -175,7 +176,7 @@
 CMSAPI cmsBool           CMSEXPORT  _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n);
 CMSAPI cmsBool           CMSEXPORT  _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n);
 CMSAPI cmsBool           CMSEXPORT  _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n);
-CMSAPI cmsBool           CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n);
+CMSAPI cmsBool           CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n);
 CMSAPI cmsBool           CMSEXPORT  _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n);
 CMSAPI cmsBool           CMSEXPORT  _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ);
 CMSAPI cmsBool           CMSEXPORT  _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array);
@@ -209,6 +210,11 @@
 CMSAPI void                CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source);
 CMSAPI void                CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest);
 
+//----------------------------------------------------------------------------------------------------------
+
+// Shared callbacks for user data
+typedef void     (* _cmsFreeUserDataFn)(cmsContext ContextID, void* Data);
+typedef void*    (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data);
 
 //----------------------------------------------------------------------------------------------------------
 
@@ -224,6 +230,7 @@
 #define cmsPluginRenderingIntentSig          0x696E7448     // 'intH'
 #define cmsPluginMultiProcessElementSig      0x6D706548     // 'mpeH'
 #define cmsPluginOptimizationSig             0x6F707448     // 'optH'
+#define cmsPluginTransformSig                0x7A666D48     // 'xfmH'
 
 typedef struct _cmsPluginBaseStruct {
 
@@ -414,8 +421,9 @@
         void    (* FreePtr)(struct _cms_typehandler_struct* self,
                             void *Ptr);
 
-        // The calling thread
-        cmsContext     ContextID;
+        // Additional parameters used by the calling thread
+        cmsContext       ContextID;
+        cmsUInt32Number  ICCVersion;
 
 } cmsTagTypeHandler;
 
@@ -513,6 +521,39 @@
 
 }  cmsPluginMultiProcessElement;
 
+
+// Data kept in "Element" member of cmsStage
+
+// Curves
+typedef struct {
+    cmsUInt32Number nCurves;
+    cmsToneCurve**  TheCurves;
+
+} _cmsStageToneCurvesData;
+
+// Matrix
+typedef struct {
+    cmsFloat64Number*  Double;          // floating point for the matrix
+    cmsFloat64Number*  Offset;          // The offset
+
+} _cmsStageMatrixData;
+
+// CLUT
+typedef struct {
+
+    union {                       // Can have only one of both representations at same time
+        cmsUInt16Number*  T;      // Points to the table 16 bits table
+        cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table
+
+    } Tab;
+
+    cmsInterpParams* Params;
+    cmsUInt32Number  nEntries;
+    cmsBool          HasFloatValues;
+
+} _cmsStageCLutData;
+
+
 //----------------------------------------------------------------------------------------------------------
 // Optimization. Using this plug-in, additional optimization strategies may be implemented.
 // The function should return TRUE if any optimization is done on the LUT, this terminates
@@ -523,9 +564,6 @@
                                      register cmsUInt16Number Out[],
                                      register const void* Data);
 
-typedef void     (* _cmsOPTfreeDataFn)(cmsContext ContextID, void* Data);
-typedef void*    (* _cmsOPTdupDataFn)(cmsContext ContextID, const void* Data);
-
 
 typedef cmsBool  (* _cmsOPToptimizeFn)(cmsPipeline** Lut,
                                        cmsUInt32Number  Intent,
@@ -539,8 +577,8 @@
 CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
                                                _cmsOPTeval16Fn Eval16,
                                                void* PrivateData,
-                                               _cmsOPTfreeDataFn FreePrivateDataFn,
-                                               _cmsOPTdupDataFn DupPrivateDataFn);
+                                               _cmsFreeUserDataFn FreePrivateDataFn,
+                                               _cmsDupUserDataFn DupPrivateDataFn);
 
 typedef struct {
       cmsPluginBase     base;
@@ -551,6 +589,39 @@
 }  cmsPluginOptimization;
 
 //----------------------------------------------------------------------------------------------------------
+// Full xform
+typedef void     (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo,
+                                     const void* InputBuffer,
+                                     void* OutputBuffer,
+                                     cmsUInt32Number Size,
+                                     cmsUInt32Number Stride);
+
+typedef cmsBool  (* _cmsTransformFactory)(_cmsTransformFn* xform,
+                                         void** UserData,
+                                         _cmsFreeUserDataFn* FreePrivateDataFn,
+                                         cmsPipeline** Lut,
+                                         cmsUInt32Number* InputFormat,
+                                         cmsUInt32Number* OutputFormat,
+                                         cmsUInt32Number* dwFlags);
+
+
+// Retrieve user data as specified by the factory
+CMSAPI void   CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn);
+CMSAPI void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo);
+
+
+// Retrieve formatters
+CMSAPI void   CMSEXPORT _cmsGetTransformFormatters16   (struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput);
+CMSAPI void   CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput);
+
+typedef struct {
+      cmsPluginBase     base;
+
+      // Transform entry point
+      _cmsTransformFactory  Factory;
+
+}  cmsPluginTransform;
+
 
 #ifndef CMS_USE_CPP_API
 #   ifdef __cplusplus
