changeset 7984:a07c907a82b5

7043064: sun/java2d/cmm/ tests failed against RI b141 & b138-nightly Reviewed-by: prr, vadim
author bae
date Wed, 04 Sep 2013 12:10:07 +0400
parents 2114b624bf63
children c561115d697d
files make/sun/cmm/lcms/mapfile-vers makefiles/mapfiles/liblcms/mapfile-vers src/share/classes/java/awt/color/ICC_Profile.java src/share/classes/java/awt/color/ICC_ProfileGray.java src/share/classes/java/awt/color/ICC_ProfileRGB.java src/share/classes/sun/java2d/cmm/CMSManager.java src/share/classes/sun/java2d/cmm/PCMM.java src/share/classes/sun/java2d/cmm/Profile.java src/share/classes/sun/java2d/cmm/lcms/LCMS.java src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java src/share/native/sun/java2d/cmm/lcms/LCMS.c test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java
diffstat 13 files changed, 547 insertions(+), 305 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/cmm/lcms/mapfile-vers	Sun Sep 01 09:38:03 2013 -0700
+++ b/make/sun/cmm/lcms/mapfile-vers	Wed Sep 04 12:10:07 2013 +0400
@@ -28,9 +28,8 @@
 SUNWprivate_1.1 {
 	global:
         Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
         Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
--- a/makefiles/mapfiles/liblcms/mapfile-vers	Sun Sep 01 09:38:03 2013 -0700
+++ b/makefiles/mapfiles/liblcms/mapfile-vers	Wed Sep 04 12:10:07 2013 +0400
@@ -28,9 +28,8 @@
 SUNWprivate_1.1 {
 	global:
         Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
         Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
--- a/src/share/classes/java/awt/color/ICC_Profile.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/java/awt/color/ICC_Profile.java	Wed Sep 04 12:10:07 2013 +0400
@@ -37,6 +37,7 @@
 
 import sun.java2d.cmm.PCMM;
 import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.Profile;
 import sun.java2d.cmm.ProfileDataVerifier;
 import sun.java2d.cmm.ProfileDeferralMgr;
 import sun.java2d.cmm.ProfileDeferralInfo;
@@ -94,7 +95,7 @@
 
     private static final long serialVersionUID = -3938515861990936766L;
 
-    transient long ID;
+    private transient Profile cmmProfile;
 
     private transient ProfileDeferralInfo deferralInfo;
     private transient ProfileActivator profileActivator;
@@ -727,8 +728,8 @@
     /**
      * Constructs an ICC_Profile object with a given ID.
      */
-    ICC_Profile(long ID) {
-        this.ID = ID;
+    ICC_Profile(Profile p) {
+        this.cmmProfile = p;
     }
 
 
@@ -751,8 +752,8 @@
      * Frees the resources associated with an ICC_Profile object.
      */
     protected void finalize () {
-        if (ID != 0) {
-            CMSManager.getModule().freeProfile(ID);
+        if (cmmProfile != null) {
+            CMSManager.getModule().freeProfile(cmmProfile);
         } else if (profileActivator != null) {
             ProfileDeferralMgr.unregisterDeferral(profileActivator);
         }
@@ -770,7 +771,7 @@
     public static ICC_Profile getInstance(byte[] data) {
     ICC_Profile thisProfile;
 
-        long theID;
+        Profile p = null;
 
         if (ProfileDeferralMgr.deferring) {
             ProfileDeferralMgr.activateProfiles();
@@ -779,32 +780,32 @@
         ProfileDataVerifier.verify(data);
 
         try {
-            theID = CMSManager.getModule().loadProfile(data);
+            p = CMSManager.getModule().loadProfile(data);
         } catch (CMMException c) {
             throw new IllegalArgumentException("Invalid ICC Profile Data");
         }
 
         try {
-            if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
-                (getData (theID, icSigMediaWhitePointTag) != null) &&
-                (getData (theID, icSigGrayTRCTag) != null)) {
-                thisProfile = new ICC_ProfileGray (theID);
+            if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
+                (getData (p, icSigMediaWhitePointTag) != null) &&
+                (getData (p, icSigGrayTRCTag) != null)) {
+                thisProfile = new ICC_ProfileGray (p);
             }
-            else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
-                (getData (theID, icSigMediaWhitePointTag) != null) &&
-                (getData (theID, icSigRedColorantTag) != null) &&
-                (getData (theID, icSigGreenColorantTag) != null) &&
-                (getData (theID, icSigBlueColorantTag) != null) &&
-                (getData (theID, icSigRedTRCTag) != null) &&
-                (getData (theID, icSigGreenTRCTag) != null) &&
-                (getData (theID, icSigBlueTRCTag) != null)) {
-                thisProfile = new ICC_ProfileRGB (theID);
+            else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
+                (getData (p, icSigMediaWhitePointTag) != null) &&
+                (getData (p, icSigRedColorantTag) != null) &&
+                (getData (p, icSigGreenColorantTag) != null) &&
+                (getData (p, icSigBlueColorantTag) != null) &&
+                (getData (p, icSigRedTRCTag) != null) &&
+                (getData (p, icSigGreenTRCTag) != null) &&
+                (getData (p, icSigBlueTRCTag) != null)) {
+                thisProfile = new ICC_ProfileRGB (p);
             }
             else {
-                thisProfile = new ICC_Profile (theID);
+                thisProfile = new ICC_Profile (p);
             }
         } catch (CMMException c) {
-            thisProfile = new ICC_Profile (theID);
+            thisProfile = new ICC_Profile (p);
         }
         return thisProfile;
     }
@@ -1119,7 +1120,7 @@
                 fileName);
         }
         try {
-            ID = CMSManager.getModule().loadProfile(profileData);
+            cmmProfile = CMSManager.getModule().loadProfile(profileData);
         } catch (CMMException c) {
             ProfileDataException pde = new
                 ProfileDataException("Invalid ICC Profile Data" + fileName);
@@ -1229,14 +1230,14 @@
                                                    causing a deferred profile
                                                    to be loaded */
         }
-        return    getColorSpaceType(ID);
+        return    getColorSpaceType(cmmProfile);
     }
 
-    static int getColorSpaceType(long profileID) {
+    static int getColorSpaceType(Profile p) {
     byte[] theHeader;
     int theColorSpaceSig, theColorSpace;
 
-        theHeader = getData(profileID, icSigHead);
+        theHeader = getData(p, icSigHead);
         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
         theColorSpace = iccCStoJCS (theColorSpaceSig);
         return theColorSpace;
@@ -1258,15 +1259,15 @@
         if (ProfileDeferralMgr.deferring) {
             ProfileDeferralMgr.activateProfiles();
         }
-        return getPCSType(ID);
+        return getPCSType(cmmProfile);
     }
 
 
-    static int getPCSType(long profileID) {
+    static int getPCSType(Profile p) {
     byte[] theHeader;
     int thePCSSig, thePCS;
 
-        theHeader = getData(profileID, icSigHead);
+        theHeader = getData(p, icSigHead);
         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
         thePCS = iccCStoJCS(thePCSSig);
         return thePCS;
@@ -1326,12 +1327,12 @@
         PCMM mdl = CMSManager.getModule();
 
         /* get the number of bytes needed for this profile */
-        profileSize = mdl.getProfileSize(ID);
+        profileSize = mdl.getProfileSize(cmmProfile);
 
         profileData = new byte [profileSize];
 
         /* get the data for the profile */
-        mdl.getProfileData(ID, profileData);
+        mdl.getProfileData(cmmProfile, profileData);
 
         return profileData;
     }
@@ -1358,11 +1359,11 @@
             ProfileDeferralMgr.activateProfiles();
         }
 
-        return getData(ID, tagSignature);
+        return getData(cmmProfile, tagSignature);
     }
 
 
-    static byte[] getData(long profileID, int tagSignature) {
+    static byte[] getData(Profile p, int tagSignature) {
     int tagSize;
     byte[] tagData;
 
@@ -1370,12 +1371,12 @@
             PCMM mdl = CMSManager.getModule();
 
             /* get the number of bytes needed for this tag */
-            tagSize = mdl.getTagSize(profileID, tagSignature);
+            tagSize = mdl.getTagSize(p, tagSignature);
 
             tagData = new byte[tagSize]; /* get an array for the tag */
 
             /* get the tag's data */
-            mdl.getTagData(profileID, tagSignature, tagData);
+            mdl.getTagData(p, tagSignature, tagData);
         } catch(CMMException c) {
             tagData = null;
         }
@@ -1406,7 +1407,7 @@
             ProfileDeferralMgr.activateProfiles();
         }
 
-        CMSManager.getModule().setTagData(ID, tagSignature, tagData);
+        CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
     }
 
     /**
--- a/src/share/classes/java/awt/color/ICC_ProfileGray.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/java/awt/color/ICC_ProfileGray.java	Wed Sep 04 12:10:07 2013 +0400
@@ -35,7 +35,7 @@
 
 package java.awt.color;
 
-import java.awt.image.LookupTable;
+import sun.java2d.cmm.Profile;
 import sun.java2d.cmm.ProfileDeferralInfo;
 
 /**
@@ -76,8 +76,8 @@
     /**
      * Constructs a new ICC_ProfileGray from a CMM ID.
      */
-    ICC_ProfileGray(long ID) {
-        super(ID);
+    ICC_ProfileGray(Profile p) {
+        super(p);
     }
 
     /**
--- a/src/share/classes/java/awt/color/ICC_ProfileRGB.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/java/awt/color/ICC_ProfileRGB.java	Wed Sep 04 12:10:07 2013 +0400
@@ -35,7 +35,7 @@
 
 package java.awt.color;
 
-import java.awt.image.LookupTable;
+import sun.java2d.cmm.Profile;
 import sun.java2d.cmm.ProfileDeferralInfo;
 
 /**
@@ -114,8 +114,8 @@
      * @param ID The CMM ID for the profile.
      *
      */
-    ICC_ProfileRGB(long ID) {
-        super(ID);
+    ICC_ProfileRGB(Profile p) {
+        super(p);
     }
 
     /**
--- a/src/share/classes/sun/java2d/cmm/CMSManager.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/sun/java2d/cmm/CMSManager.java	Wed Sep 04 12:10:07 2013 +0400
@@ -104,53 +104,53 @@
             cName = tcmm.getClass().getName();
         }
 
-        public long loadProfile(byte[] data) {
+        public Profile loadProfile(byte[] data) {
             System.err.print(cName + ".loadProfile");
-            long profileID = tcmm.loadProfile(data);
-            System.err.printf("(ID=%x)\n", profileID);
-            return profileID;
+            Profile p = tcmm.loadProfile(data);
+            System.err.printf("(ID=%s)\n", p.toString());
+            return p;
         }
 
-        public void freeProfile(long profileID) {
-            System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID);
-            tcmm.freeProfile(profileID);
+        public void freeProfile(Profile p) {
+            System.err.printf(cName + ".freeProfile(ID=%s)\n", p.toString());
+            tcmm.freeProfile(p);
         }
 
-        public int getProfileSize(long profileID) {
-            System.err.print(cName + ".getProfileSize(ID=" + profileID + ")");
-            int size = tcmm.getProfileSize(profileID);
+        public int getProfileSize(Profile p) {
+            System.err.print(cName + ".getProfileSize(ID=" + p + ")");
+            int size = tcmm.getProfileSize(p);
             System.err.println("=" + size);
             return size;
         }
 
-        public void getProfileData(long profileID, byte[] data) {
-            System.err.print(cName + ".getProfileData(ID=" + profileID + ") ");
+        public void getProfileData(Profile p, byte[] data) {
+            System.err.print(cName + ".getProfileData(ID=" + p + ") ");
             System.err.println("requested " + data.length + " byte(s)");
-            tcmm.getProfileData(profileID, data);
+            tcmm.getProfileData(p, data);
         }
 
-        public int getTagSize(long profileID, int tagSignature) {
+        public int getTagSize(Profile p, int tagSignature) {
             System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)",
-                              profileID, signatureToString(tagSignature));
-            int size = tcmm.getTagSize(profileID, tagSignature);
+                              p, signatureToString(tagSignature));
+            int size = tcmm.getTagSize(p, tagSignature);
             System.err.println("=" + size);
             return size;
         }
 
-        public void getTagData(long profileID, int tagSignature,
+        public void getTagData(Profile p, int tagSignature,
                                byte[] data) {
             System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)",
-                              profileID, signatureToString(tagSignature));
+                              p, signatureToString(tagSignature));
             System.err.println(" requested " + data.length + " byte(s)");
-            tcmm.getTagData(profileID, tagSignature, data);
+            tcmm.getTagData(p, tagSignature, data);
         }
 
-        public void setTagData(long profileID, int tagSignature,
+        public void setTagData(Profile p, int tagSignature,
                                byte[] data) {
-            System.err.print(cName + ".setTagData(ID=" + profileID +
+            System.err.print(cName + ".setTagData(ID=" + p +
                              ", TagSig=" + tagSignature + ")");
             System.err.println(" sending " + data.length + " byte(s)");
-            tcmm.setTagData(profileID, tagSignature, data);
+            tcmm.setTagData(p, tagSignature, data);
         }
 
         /* methods for creating ColorTransforms */
--- a/src/share/classes/sun/java2d/cmm/PCMM.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/sun/java2d/cmm/PCMM.java	Wed Sep 04 12:10:07 2013 +0400
@@ -32,13 +32,13 @@
 public interface PCMM {
 
     /* methods invoked from ICC_Profile */
-    public long loadProfile(byte[] data);
-    public void freeProfile(long profileID);
-    public int  getProfileSize(long profileID);
-    public void getProfileData(long profileID, byte[] data);
-    public void getTagData(long profileID, int tagSignature, byte[] data);
-    public int getTagSize(long profileID, int tagSignature);
-    public void setTagData(long profileID, int tagSignature, byte[] data);
+    public Profile loadProfile(byte[] data);
+    public void freeProfile(Profile p);
+    public int  getProfileSize(Profile p);
+    public void getProfileData(Profile p, byte[] data);
+    public void getTagData(Profile p, int tagSignature, byte[] data);
+    public int getTagSize(Profile p, int tagSignature);
+    public void setTagData(Profile p, int tagSignature, byte[] data);
 
     /* methods for creating ColorTransforms */
     public ColorTransform createTransform(ICC_Profile profile, int renderType,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/java2d/cmm/Profile.java	Wed Sep 04 12:10:07 2013 +0400
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package sun.java2d.cmm;
+
+import java.awt.color.CMMException;
+
+public class Profile {
+    private final long nativePtr;
+
+    protected Profile(long ptr) {
+        nativePtr = ptr;
+    }
+
+    protected final long getNativePtr() {
+        if (nativePtr == 0L) {
+            throw new CMMException("Invalid profile: ptr is null");
+        }
+        return nativePtr;
+    }
+}
--- a/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Wed Sep 04 12:10:07 2013 +0400
@@ -25,96 +25,139 @@
 
 package sun.java2d.cmm.lcms;
 
+import java.awt.color.CMMException;
 import java.awt.color.ICC_Profile;
-import java.util.Arrays;
-import java.util.HashMap;
 import sun.java2d.cmm.ColorTransform;
 import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.Profile;
+import sun.java2d.cmm.lcms.LCMSProfile.TagData;
 
 public class LCMS implements PCMM {
 
     /* methods invoked from ICC_Profile */
     @Override
-    public long loadProfile(byte[] data) {
-        long id = loadProfileNative(data);
+    public Profile loadProfile(byte[] data) {
+        final Object disposerRef = new Object();
 
-        if (id != 0L) {
-            if (profiles == null) {
-                profiles = new HashMap<>();
-            }
-            profiles.put(id, new TagCache(id));
+        final long ptr = loadProfileNative(data, disposerRef);
+
+        if (ptr != 0L) {
+            return new LCMSProfile(ptr, disposerRef);
         }
-        return id;
+        return null;
     }
 
-    private native long loadProfileNative(byte[] data);
+    private native long loadProfileNative(byte[] data, Object ref);
+
+    private LCMSProfile getLcmsProfile(Profile p) {
+        if (p instanceof LCMSProfile) {
+            return (LCMSProfile)p;
+        }
+        throw new CMMException("Invalid profile: " + p);
+    }
+
 
     @Override
-    public void freeProfile(long profileID) {
-        TagCache c = profiles.remove(profileID);
-        if (c != null) {
-            c.clear();
-        }
-        if (profiles.isEmpty()) {
-            profiles = null;
-        }
-        freeProfileNative(profileID);
+    public void freeProfile(Profile p) {
+        // we use disposer, so this method does nothing
     }
 
-    private native void freeProfileNative(long profileID);
+    @Override
+    public int getProfileSize(final Profile p) {
+        synchronized (p) {
+            return getProfileSizeNative(getLcmsProfile(p).getLcmsPtr());
+        }
+    }
 
-    public native synchronized int getProfileSize(long profileID);
-
-    public native synchronized void getProfileData(long profileID, byte[] data);
+    private native int getProfileSizeNative(long ptr);
 
     @Override
-    public synchronized int getTagSize(long profileID, int tagSignature) {
-        TagCache cache = profiles.get(profileID);
-
-        if (cache ==  null) {
-            cache = new TagCache(profileID);
-            profiles.put(profileID, cache);
+    public void getProfileData(final Profile p, byte[] data) {
+        synchronized (p) {
+            getProfileDataNative(getLcmsProfile(p).getLcmsPtr(), data);
         }
-
-        TagData t = cache.getTag(tagSignature);
-        return t == null ? 0 : t.getSize();
     }
 
-    private static native byte[] getTagNative(long profileID, int signature);
+    private native void getProfileDataNative(long ptr, byte[] data);
 
     @Override
-    public synchronized void getTagData(long profileID, int tagSignature,
-                                               byte[] data)
+    public int getTagSize(Profile p, int tagSignature) {
+        final LCMSProfile profile = getLcmsProfile(p);
+
+        synchronized (profile) {
+            TagData t = profile.getTag(tagSignature);
+            return t == null ? 0 : t.getSize();
+        }
+    }
+
+    static native byte[] getTagNative(long profileID, int signature);
+
+    @Override
+    public void getTagData(Profile p, int tagSignature, byte[] data)
     {
-        TagCache cache = profiles.get(profileID);
+        final LCMSProfile profile = getLcmsProfile(p);
 
-        if (cache ==  null) {
-            cache = new TagCache(profileID);
-            profiles.put(profileID, cache);
-        }
-
-        TagData t = cache.getTag(tagSignature);
-        if (t != null) {
-            t.copyDataTo(data);
+        synchronized (profile) {
+            TagData t = profile.getTag(tagSignature);
+            if (t != null) {
+                t.copyDataTo(data);
+            }
         }
     }
 
     @Override
-    public synchronized void setTagData(long profileID, int tagSignature, byte[] data) {
-        TagCache cache = profiles.get(profileID);
+    public synchronized void setTagData(Profile p, int tagSignature, byte[] data) {
+        final LCMSProfile profile = getLcmsProfile(p);
 
-        if (cache != null) {
-            cache.clear();
+        synchronized (profile) {
+            profile.clearTagCache();
+
+            // Now we are going to update the profile with new tag data
+            // In some cases, we may change the pointer to the native
+            // profile.
+            //
+            // If we fail to write tag data for any reason, the old pointer
+            // should be used.
+            setTagDataNative(profile.getLcmsPtr(),
+                    tagSignature, data);
         }
-        setTagDataNative(profileID, tagSignature, data);
     }
 
-    private native synchronized void setTagDataNative(long profileID, int tagSignature,
+    /**
+     * Writes supplied data as a tag into the profile.
+     * Destroys old profile, if new one was successfully
+     * created.
+     *
+     * Returns valid pointer to new profile.
+     *
+     * Throws CMMException if operation fails, preserve old profile from
+     * destruction.
+     */
+    private native void setTagDataNative(long ptr, int tagSignature,
                                                byte[] data);
 
-    public static native long getProfileID(ICC_Profile profile);
+    public synchronized static native LCMSProfile getProfileID(ICC_Profile profile);
 
-    public static native long createNativeTransform(
+    /* Helper method used from LCMSColorTransfrom */
+    static long createTransform(
+        LCMSProfile[] profiles, int renderType,
+        int inFormatter, boolean isInIntPacked,
+        int outFormatter, boolean isOutIntPacked,
+        Object disposerRef)
+    {
+        long[] ptrs = new long[profiles.length];
+
+        for (int i = 0; i < profiles.length; i++) {
+            if (profiles[i] == null) throw new CMMException("Unknown profile ID");
+
+            ptrs[i] = profiles[i].getLcmsPtr();
+        }
+
+        return createNativeTransform(ptrs, renderType, inFormatter,
+                isInIntPacked, outFormatter, isOutIntPacked, disposerRef);
+    }
+
+    private static native long createNativeTransform(
         long[] profileIDs, int renderType,
         int inFormatter, boolean isInIntPacked,
         int outFormatter, boolean isOutIntPacked,
@@ -175,59 +218,4 @@
 
         return theLcms;
     }
-
-    private static class TagData {
-        private int signature;
-        private byte[] data;
-
-        TagData(int sig, byte[] data) {
-            this.signature = sig;
-            this.data = data;
-        }
-
-        int getSize() {
-            return data.length;
-        }
-
-        byte[] getData() {
-            return Arrays.copyOf(data, data.length);
-        }
-
-        void copyDataTo(byte[] dst) {
-            System.arraycopy(data, 0, dst, 0, data.length);
-        }
-
-        int getSignature() {
-            return signature;
-        }
-    }
-
-    private static class TagCache  {
-        private long profileID;
-        private HashMap<Integer, TagData> tags;
-
-        TagCache(long id) {
-            profileID = id;
-
-            tags = new HashMap<>();
-        }
-
-        TagData getTag(int sig) {
-            TagData t = tags.get(sig);
-            if (t == null) {
-                byte[] tagData = getTagNative(profileID, sig);
-                if (tagData != null) {
-                    t = new TagData(sig, tagData);
-                    tags.put(sig, t);
-                }
-            }
-            return t;
-        }
-
-        void clear() {
-            tags.clear();
-        }
-    }
-
-    private static HashMap<Long, TagCache> profiles;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java	Wed Sep 04 12:10:07 2013 +0400
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package sun.java2d.cmm.lcms;
+
+import java.awt.color.CMMException;
+import java.util.Arrays;
+import java.util.HashMap;
+import sun.java2d.cmm.Profile;
+
+final class LCMSProfile extends Profile {
+    private final TagCache tagCache;
+
+    private final Object disposerReferent;
+
+    LCMSProfile(long ptr, Object ref) {
+        super(ptr);
+
+        disposerReferent = ref;
+
+        tagCache = new TagCache(this);
+    }
+
+    final long getLcmsPtr() {
+        return this.getNativePtr();
+    }
+
+    TagData getTag(int sig) {
+        return tagCache.getTag(sig);
+    }
+
+    void clearTagCache() {
+        tagCache.clear();
+    }
+
+    static class TagCache  {
+        final LCMSProfile profile;
+        private HashMap<Integer, TagData> tags;
+
+        TagCache(LCMSProfile p) {
+            profile = p;
+            tags = new HashMap<>();
+        }
+
+        TagData getTag(int sig) {
+            TagData t = tags.get(sig);
+            if (t == null) {
+                byte[] tagData = LCMS.getTagNative(profile.getNativePtr(), sig);
+                if (tagData != null) {
+                    t = new TagData(sig, tagData);
+                    tags.put(sig, t);
+                }
+            }
+            return t;
+        }
+
+        void clear() {
+            tags.clear();
+        }
+    }
+
+    static class TagData {
+        private int signature;
+        private byte[] data;
+
+        TagData(int sig, byte[] data) {
+            this.signature = sig;
+            this.data = data;
+        }
+
+        int getSize() {
+            return data.length;
+        }
+
+        byte[] getData() {
+            return Arrays.copyOf(data, data.length);
+        }
+
+        void copyDataTo(byte[] dst) {
+            System.arraycopy(data, 0, dst, 0, data.length);
+        }
+
+        int getSignature() {
+            return signature;
+        }
+    }
+}
--- a/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Wed Sep 04 12:10:07 2013 +0400
@@ -62,7 +62,7 @@
     private boolean isOutIntPacked = false;
 
     ICC_Profile[] profiles;
-    long [] profileIDs;
+    LCMSProfile[] lcmsProfiles;
     int renderType;
     int transformType;
 
@@ -84,8 +84,8 @@
         /* Actually, it is not a complete transform but just part of it */
         profiles = new ICC_Profile[1];
         profiles[0] = profile;
-        profileIDs = new long[1];
-        profileIDs[0] = LCMS.getProfileID(profile);
+        lcmsProfiles = new LCMSProfile[1];
+        lcmsProfiles[0] = LCMS.getProfileID(profile);
         this.renderType = (renderType == ColorTransform.Any)?
                               ICC_Profile.icPerceptual : renderType;
         this.transformType = transformType;
@@ -105,14 +105,14 @@
             size+=((LCMSTransform)transforms[i]).profiles.length;
         }
         profiles = new ICC_Profile[size];
-        profileIDs = new long[size];
+        lcmsProfiles = new LCMSProfile[size];
         int j = 0;
         for (int i=0; i < transforms.length; i++) {
             LCMSTransform curTrans = (LCMSTransform)transforms[i];
             System.arraycopy(curTrans.profiles, 0, profiles, j,
                              curTrans.profiles.length);
-            System.arraycopy(curTrans.profileIDs, 0, profileIDs, j,
-                             curTrans.profileIDs.length);
+            System.arraycopy(curTrans.lcmsProfiles, 0, lcmsProfiles, j,
+                             curTrans.lcmsProfiles.length);
             j += curTrans.profiles.length;
         }
         renderType = ((LCMSTransform)transforms[0]).renderType;
@@ -152,7 +152,7 @@
             outFormatter = out.pixelType;
             isOutIntPacked = out.isIntPacked;
 
-            ID = LCMS.createNativeTransform(profileIDs, renderType,
+            ID = LCMS.createTransform(lcmsProfiles, renderType,
                                             inFormatter, isInIntPacked,
                                             outFormatter, isOutIntPacked,
                                             disposerReferent);
--- a/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Sun Sep 01 09:38:03 2013 -0700
+++ b/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Wed Sep 04 12:10:07 2013 +0400
@@ -94,8 +94,12 @@
 # endif
 #endif
 
+typedef struct lcmsProfile_s {
+    cmsHPROFILE pf;
+} lcmsProfile_t, *lcmsProfile_p;
+
 typedef union storeID_s {    /* store SProfile stuff in a Java Long */
-    cmsHPROFILE pf;
+    lcmsProfile_p lcmsPf;
     cmsHTRANSFORM xf;
     jobject jobj;
     jlong j;
@@ -106,7 +110,6 @@
     jint j;
 } TagSignature_t, *TagSignature_p;
 
-static jfieldID Trans_profileIDs_fID;
 static jfieldID Trans_renderType_fID;
 static jfieldID Trans_ID_fID;
 static jfieldID IL_isIntPacked_fID;
@@ -118,7 +121,6 @@
 static jfieldID IL_width_fID;
 static jfieldID IL_height_fID;
 static jfieldID IL_imageAtOnce_fID;
-static jfieldID PF_ID_fID;
 
 JavaVM *javaVM;
 
@@ -145,6 +147,18 @@
     return JNI_VERSION_1_6;
 }
 
+void LCMS_freeProfile(JNIEnv *env, jlong ptr) {
+    storeID_t sProfile;
+    sProfile.j = ptr;
+
+    if (sProfile.lcmsPf != NULL) {
+        if (sProfile.lcmsPf->pf != NULL) {
+            cmsCloseProfile(sProfile.lcmsPf->pf);
+        }
+        free(sProfile.lcmsPf);
+    }
+}
+
 void LCMS_freeTransform(JNIEnv *env, jlong ID)
 {
     storeID_t sTrans;
@@ -170,7 +184,7 @@
     jlong* ids;
 
     size = (*env)->GetArrayLength (env, profileIDs);
-    ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0);
+    ids = (*env)->GetLongArrayElements(env, profileIDs, 0);
 
 #ifdef _LITTLE_ENDIAN
     /* Reversing data packed into int for LE archs */
@@ -186,6 +200,8 @@
         iccArray = (cmsHPROFILE*) malloc(
             size*2*sizeof(cmsHPROFILE));
         if (iccArray == NULL) {
+            (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
+
             J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
             return 0L;
         }
@@ -197,7 +213,7 @@
         cmsColorSpaceSignature cs;
 
         sTrans.j = ids[i];
-        icc = sTrans.pf;
+        icc = sTrans.lcmsPf->pf;
         iccArray[j++] = icc;
 
         /* Middle non-abstract profiles should be doubled before passing to
@@ -215,13 +231,15 @@
     sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j,
         inFormatter, outFormatter, renderType, 0);
 
-    (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0);
+    (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
 
     if (sTrans.xf == NULL) {
         J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "
                                        "sTrans.xf == NULL");
-        JNU_ThrowByName(env, "java/awt/color/CMMException",
-                        "Cannot get color transform");
+        if ((*env)->ExceptionOccurred(env) == NULL) {
+            JNU_ThrowByName(env, "java/awt/color/CMMException",
+                            "Cannot get color transform");
+        }
     } else {
         Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
     }
@@ -236,20 +254,23 @@
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    loadProfile
- * Signature: ([B)J
+ * Signature: ([B,Lsun/java2d/cmm/lcms/LCMSProfile;)V
  */
 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative
-  (JNIEnv *env, jobject obj, jbyteArray data)
+  (JNIEnv *env, jobject obj, jbyteArray data, jobject disposerRef)
 {
     jbyte* dataArray;
     jint dataSize;
     storeID_t sProf;
+    cmsHPROFILE pf;
 
     if (JNU_IsNull(env, data)) {
         JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
         return 0L;
     }
 
+    sProf.j = 0L;
+
     dataArray = (*env)->GetByteArrayElements (env, data, 0);
     dataSize = (*env)->GetArrayLength (env, data);
 
@@ -258,22 +279,37 @@
         return 0L;
     }
 
-    sProf.pf = cmsOpenProfileFromMem((const void *)dataArray,
+    pf = cmsOpenProfileFromMem((const void *)dataArray,
                                      (cmsUInt32Number) dataSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
-    if (sProf.pf == NULL) {
+    if (pf == NULL) {
         JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
     } else {
         /* Sanity check: try to save the profile in order
          * to force basic validation.
          */
         cmsUInt32Number pfSize = 0;
-        if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) ||
+        if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
             pfSize < sizeof(cmsICCHeader))
         {
             JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
+
+            cmsCloseProfile(pf);
+            pf = NULL;
+        }
+    }
+
+    if (pf != NULL) {
+        // create profile holder
+        sProf.lcmsPf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));
+        if (sProf.lcmsPf != NULL) {
+            // register the disposer record
+            sProf.lcmsPf->pf = pf;
+            Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sProf.j);
+        } else {
+            cmsCloseProfile(pf);
         }
     }
 
@@ -282,37 +318,17 @@
 
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
- * Method:    freeProfile
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative
-  (JNIEnv *env, jobject obj, jlong id)
-{
-    storeID_t sProf;
-
-    sProf.j = id;
-    if (cmsCloseProfile(sProf.pf) == 0) {
-        J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)"
-                       "== 0", id);
-        JNU_ThrowByName(env, "java/awt/color/CMMException",
-                        "Cannot close profile");
-    }
-
-}
-
-/*
- * Class:     sun_java2d_cmm_lcms_LCMS
- * Method:    getProfileSize
+ * Method:    getProfileSizeNative
  * Signature: (J)I
  */
-JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize
+JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative
   (JNIEnv *env, jobject obj, jlong id)
 {
     storeID_t sProf;
     cmsUInt32Number pfSize = 0;
     sProf.j = id;
 
-    if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
+    if (cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
         return (jint)pfSize;
     } else {
       JNU_ThrowByName(env, "java/awt/color/CMMException",
@@ -323,10 +339,10 @@
 
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
- * Method:    getProfileData
+ * Method:    getProfileDataNative
  * Signature: (J[B)V
  */
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData
+JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative
   (JNIEnv *env, jobject obj, jlong id, jbyteArray data)
 {
     storeID_t sProf;
@@ -338,7 +354,7 @@
     sProf.j = id;
 
     // determine actual profile size
-    if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) {
+    if (!cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize)) {
         JNU_ThrowByName(env, "java/awt/color/CMMException",
                         "Can not access specified profile.");
         return;
@@ -354,7 +370,7 @@
 
     dataArray = (*env)->GetByteArrayElements (env, data, 0);
 
-    status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize);
+    status = cmsSaveProfileToMem(sProf.lcmsPf->pf, dataArray, &pfSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -368,7 +384,7 @@
 /* Get profile header info */
 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
 static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
-static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
+static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
 
 
 /*
@@ -412,7 +428,7 @@
            return NULL;
         }
 
-        status = _getHeaderInfo(sProf.pf, dataArray, bufSize);
+        status = _getHeaderInfo(sProf.lcmsPf->pf, dataArray, bufSize);
 
         (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -425,8 +441,8 @@
         return data;
     }
 
-    if (cmsIsTag(sProf.pf, sig.cms)) {
-        tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
+    if (cmsIsTag(sProf.lcmsPf->pf, sig.cms)) {
+        tagSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, NULL, 0);
     } else {
         JNU_ThrowByName(env, "java/awt/color/CMMException",
                         "ICC profile tag not found");
@@ -449,7 +465,7 @@
         return NULL;
     }
 
-    bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);
+    bufSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -470,8 +486,10 @@
   (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
 {
     storeID_t sProf;
+    cmsHPROFILE pfReplace = NULL;
+
     TagSignature_t sig;
-    cmsBool status;
+    cmsBool status = FALSE;
     jbyte* dataArray;
     int tagSize;
 
@@ -493,15 +511,24 @@
     }
 
     if (tagSig == SigHead) {
-        status = _setHeaderInfo(sProf.pf, dataArray, tagSize);
+        status  = _setHeaderInfo(sProf.lcmsPf->pf, dataArray, tagSize);
     } else {
-        status = _writeCookedTag(sProf.pf, sig.cms, dataArray, tagSize);
+        /*
+        * New strategy for generic tags: create a place holder,
+        * dump all existing tags there, dump externally supplied
+        * tag, and return the new profile to the java.
+        */
+        pfReplace = _writeCookedTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize);
+        status = (pfReplace != NULL);
     }
 
     (*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
 
     if (!status) {
         JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");
+    } else if (pfReplace != NULL) {
+        cmsCloseProfile(sProf.lcmsPf->pf);
+        sProf.lcmsPf->pf = pfReplace;
     }
 }
 
@@ -624,12 +651,27 @@
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    getProfileID
- * Signature: (Ljava/awt/color/ICC_Profile;)J
+ * Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile
  */
-JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
+JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
   (JNIEnv *env, jclass cls, jobject pf)
 {
-    return (*env)->GetLongField (env, pf, PF_ID_fID);
+    jfieldID fid = (*env)->GetFieldID (env,
+        (*env)->GetObjectClass(env, pf),
+        "cmmProfile", "Lsun/java2d/cmm/Profile;");
+
+    jclass clsLcmsProfile = (*env)->FindClass(env,
+            "sun/java2d/cmm/lcms/LCMSProfile");
+
+    jobject cmmProfile = (*env)->GetObjectField (env, pf, fid);
+
+    if (JNU_IsNull(env, cmmProfile)) {
+        return NULL;
+    }
+    if ((*env)->IsInstanceOf(env, cmmProfile, clsLcmsProfile)) {
+        return cmmProfile;
+    }
+    return NULL;
 }
 
 /*
@@ -644,7 +686,6 @@
      * corresponding classes to avoid problems with invalidating ids by class
      * unloading
      */
-    Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J");
     Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I");
     Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J");
 
@@ -658,8 +699,6 @@
     IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");
     IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");
     IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");
-
-    PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
 }
 
 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
@@ -714,76 +753,114 @@
   return TRUE;
 }
 
-static cmsBool _writeCookedTag(cmsHPROFILE pfTarget,
-                               cmsTagSignature sig,
+/* Returns new profile handler, if it was created successfully,
+   NULL otherwise.
+   */
+static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,
+                               const cmsTagSignature sig,
                                jbyte *pData, jint size)
 {
-    cmsBool status;
     cmsUInt32Number pfSize = 0;
-    cmsUInt8Number* pfBuffer = NULL;
+    const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);
+    cmsInt32Number i;
+    cmsHPROFILE pfSanity = NULL;
+
+    cmsICCHeader hdr = { 0 };
 
     cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);
-    if (NULL != p) {
-        cmsICCHeader hdr = { 0 };
 
-        /* Populate the placeholder's header according to target profile */
-        hdr.flags = cmsGetHeaderFlags(pfTarget);
-        hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
-        hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
-        hdr.model = cmsGetHeaderModel(pfTarget);
-        hdr.pcs = cmsGetPCS(pfTarget);
-        hdr.colorSpace = cmsGetColorSpace(pfTarget);
-        hdr.deviceClass = cmsGetDeviceClass(pfTarget);
-        hdr.version = cmsGetEncodedICCversion(pfTarget);
-        cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
-        cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
+    if (NULL == p) {
+        return NULL;
+    }
 
-        cmsSetHeaderFlags(p, hdr.flags);
-        cmsSetHeaderManufacturer(p, hdr.manufacturer);
-        cmsSetHeaderModel(p, hdr.model);
-        cmsSetHeaderAttributes(p, hdr.attributes);
-        cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
-        cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
-        cmsSetPCS(p, hdr.pcs);
-        cmsSetColorSpace(p, hdr.colorSpace);
-        cmsSetDeviceClass(p, hdr.deviceClass);
-        cmsSetEncodedICCversion(p, hdr.version);
+    // Populate the placeholder's header according to target profile
+    hdr.flags = cmsGetHeaderFlags(pfTarget);
+    hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
+    hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
+    hdr.model = cmsGetHeaderModel(pfTarget);
+    hdr.pcs = cmsGetPCS(pfTarget);
+    hdr.colorSpace = cmsGetColorSpace(pfTarget);
+    hdr.deviceClass = cmsGetDeviceClass(pfTarget);
+    hdr.version = cmsGetEncodedICCversion(pfTarget);
+    cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
+    cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
 
+    cmsSetHeaderFlags(p, hdr.flags);
+    cmsSetHeaderManufacturer(p, hdr.manufacturer);
+    cmsSetHeaderModel(p, hdr.model);
+    cmsSetHeaderAttributes(p, hdr.attributes);
+    cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
+    cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
+    cmsSetPCS(p, hdr.pcs);
+    cmsSetColorSpace(p, hdr.colorSpace);
+    cmsSetDeviceClass(p, hdr.deviceClass);
+    cmsSetEncodedICCversion(p, hdr.version);
 
-        if (cmsWriteRawTag(p, sig, pData, size)) {
-            if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
-                pfBuffer = malloc(pfSize);
-                if (pfBuffer != NULL) {
-                    /* load raw profile data into the buffer */
-                    if (!cmsSaveProfileToMem(p, pfBuffer, &pfSize)) {
-                        free(pfBuffer);
-                        pfBuffer = NULL;
-                    }
+    // now write the user supplied tag
+    if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {
+        cmsCloseProfile(p);
+        return NULL;
+    }
+
+    // copy tags from the original profile
+    for (i = 0; i < tagCount; i++) {
+        cmsBool isTagReady = FALSE;
+        const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);
+        const cmsInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
+
+        if (s == sig) {
+            // skip the user supplied tag
+            continue;
+        }
+
+        // read raw tag from the original profile
+        if (tagSize > 0) {
+            cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);
+            if (buf != NULL) {
+                if (tagSize ==  cmsReadRawTag(pfTarget, s, buf, tagSize)) {
+                    // now we are ready to write the tag
+                    isTagReady = cmsWriteRawTag(p, s, buf, tagSize);
                 }
+                free(buf);
             }
         }
-        cmsCloseProfile(p);
+
+        if (!isTagReady) {
+            cmsCloseProfile(p);
+            return NULL;
+        }
     }
 
-    if (pfBuffer == NULL) {
-        return FALSE;
+    // now we have all tags moved to the new profile.
+    // do some sanity checks: write it to a memory buffer and read again.
+    if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
+        void* buf = malloc(pfSize);
+        if (buf != NULL) {
+            // load raw profile data into the buffer
+            if (cmsSaveProfileToMem(p, buf, &pfSize)) {
+                pfSanity = cmsOpenProfileFromMem(buf, pfSize);
+            }
+            free(buf);
+        }
     }
 
-    /* re-open the placeholder profile */
-    p = cmsOpenProfileFromMem(pfBuffer, pfSize);
-    free(pfBuffer);
-    status = FALSE;
+    if (pfSanity == NULL) {
+        // for some reason, we failed to save and read the updated profile
+        // It likely indicates that the profile is not correct, so we report
+        // a failure here.
+        cmsCloseProfile(p);
+        p =  NULL;
+    } else {
+        // do final check whether we can read and handle the the target tag.
+        const void* pTag = cmsReadTag(pfSanity, sig);
+        if (pTag == NULL) {
+            // the tag can not be cooked
+            cmsCloseProfile(p);
+            p = NULL;
+        }
+        cmsCloseProfile(pfSanity);
+        pfSanity = NULL;
+    }
 
-    if (p != NULL) {
-        /* Note that pCookedTag points to internal structures of the placeholder,
-         * so this data is valid only while the placeholder is open.
-         */
-        void *pCookedTag = cmsReadTag(p, sig);
-        if (pCookedTag != NULL) {
-            status = cmsWriteTag(pfTarget, sig, pCookedTag);
-        }
-        pCookedTag = NULL;
-        cmsCloseProfile(p);
-    }
-    return status;
+    return p;
 }
--- a/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java	Sun Sep 01 09:38:03 2013 -0700
+++ b/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java	Wed Sep 04 12:10:07 2013 +0400
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 6476665 6523403 6733501 7042594
+ * @bug 6476665 6523403 6733501 7042594 7043064
  * @summary Verifies reading and writing profiles and tags of the standard color
  * spaces
  * @run main ReadWriteProfileTest
@@ -82,6 +82,7 @@
 
     public void run() {
         for (int i = 0; i < cspaces.length; i++) {
+            System.out.println("Profile: " + csNames[i]);
             ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]);
             byte [] data = pf.getData();
             pf = ICC_Profile.getInstance(data);
@@ -92,6 +93,10 @@
             }
 
             for (int tagSig : tags[i].keySet()) {
+                String signature = SigToString(tagSig);
+                System.out.printf("Tag: %s\n", signature);
+                System.out.flush();
+
                 byte [] tagData = pf.getData(tagSig);
                 byte [] empty = new byte[tagData.length];
                 boolean emptyDataRejected = false;
@@ -104,15 +109,23 @@
                     throw new
                         RuntimeException("Test failed: empty tag data was not rejected.");
                 }
-                pf.setData(tagSig, tagData);
-
+                try {
+                    pf.setData(tagSig, tagData);
+                } catch (IllegalArgumentException e) {
+                    // let's ignore this exception for Kodak proprietary tags
+                    if (isKodakExtention(signature)) {
+                        System.out.println("Ignore Kodak tag: " + signature);
+                    } else {
+                        throw new RuntimeException("Test failed!", e);
+                    }
+                }
                 byte [] tagData1 = pf.getData(tagSig);
 
                 if (!Arrays.equals(tagData1, tags[i].get(tagSig)))
                 {
                     System.err.println("Incorrect result of getData(int) with" +
                                        " tag " +
-                                       Integer.toHexString(tagSig) +
+                                       SigToString(tagSig) +
                                        " of " + csNames[i] + " profile");
 
                     throw new RuntimeException("Incorrect result of " +
@@ -122,6 +135,19 @@
         }
     }
 
+    private static boolean isKodakExtention(String signature) {
+        return signature.matches("K\\d\\d\\d");
+    }
+
+    private static String SigToString(int tagSig ) {
+              return String.format("%c%c%c%c",
+                        (char)(0xff & (tagSig >> 24)),
+                        (char)(0xff & (tagSig >> 16)),
+                        (char)(0xff & (tagSig >>  8)),
+                        (char)(0xff & (tagSig)));
+
+    }
+
     public static void main(String [] args) {
         ReadWriteProfileTest test = new ReadWriteProfileTest();
         test.run();