1 /*
   2  * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.java2d.cmm.lcms;
  27 
  28 import java.awt.color.CMMException;
  29 import java.awt.color.ICC_Profile;
  30 import sun.java2d.cmm.ColorTransform;
  31 import sun.java2d.cmm.PCMM;
  32 import sun.java2d.cmm.Profile;
  33 import sun.java2d.cmm.lcms.LCMSProfile.TagData;
  34 
  35 public class LCMS implements PCMM {
  36 
  37     /* methods invoked from ICC_Profile */
  38     @Override
  39     public Profile loadProfile(byte[] data) {
  40         final Object disposerRef = new Object();
  41 
  42         final long ptr = loadProfileNative(data, disposerRef);
  43 
  44         if (ptr != 0L) {
  45             return new LCMSProfile(ptr, disposerRef);
  46         }
  47         return null;
  48     }
  49 
  50     private native long loadProfileNative(byte[] data, Object ref);
  51 
  52     private LCMSProfile getLcmsProfile(Profile p) {
  53         if (p instanceof LCMSProfile) {
  54             return (LCMSProfile)p;
  55         }
  56         throw new CMMException("Invalid profile: " + p);
  57     }
  58 
  59 
  60     @Override
  61     public void freeProfile(Profile p) {
  62         // we use disposer, so this method does nothing
  63     }
  64 
  65     @Override
  66     public int getProfileSize(final Profile p) {
  67         synchronized (p) {
  68             return getProfileSizeNative(getLcmsProfile(p).getLcmsPtr());
  69         }
  70     }
  71 
  72     private native int getProfileSizeNative(long ptr);
  73 
  74     @Override
  75     public void getProfileData(final Profile p, byte[] data) {
  76         synchronized (p) {
  77             getProfileDataNative(getLcmsProfile(p).getLcmsPtr(), data);
  78         }
  79     }
  80 
  81     private native void getProfileDataNative(long ptr, byte[] data);
  82 
  83     @Override
  84     public int getTagSize(Profile p, int tagSignature) {
  85         final LCMSProfile profile = getLcmsProfile(p);
  86 
  87         synchronized (profile) {
  88             TagData t = profile.getTag(tagSignature);
  89             return t == null ? 0 : t.getSize();
  90         }
  91     }
  92 
  93     static native byte[] getTagNative(long profileID, int signature);
  94 
  95     @Override
  96     public void getTagData(Profile p, int tagSignature, byte[] data)
  97     {
  98         final LCMSProfile profile = getLcmsProfile(p);
  99 
 100         synchronized (profile) {
 101             TagData t = profile.getTag(tagSignature);
 102             if (t != null) {
 103                 t.copyDataTo(data);
 104             }
 105         }
 106     }
 107 
 108     @Override
 109     public synchronized void setTagData(Profile p, int tagSignature, byte[] data) {
 110         final LCMSProfile profile = getLcmsProfile(p);
 111 
 112         synchronized (profile) {
 113             profile.clearTagCache();
 114 
 115             // Now we are going to update the profile with new tag data
 116             // In some cases, we may change the pointer to the native
 117             // profile.
 118             //
 119             // If we fail to write tag data for any reason, the old pointer
 120             // should be used.
 121             setTagDataNative(profile.getLcmsPtr(),
 122                     tagSignature, data);
 123         }
 124     }
 125 
 126     /**
 127      * Writes supplied data as a tag into the profile.
 128      * Destroys old profile, if new one was successfully
 129      * created.
 130      *
 131      * Returns valid pointer to new profile.
 132      *
 133      * Throws CMMException if operation fails, preserve old profile from
 134      * destruction.
 135      */
 136     private native void setTagDataNative(long ptr, int tagSignature,
 137                                                byte[] data);
 138 
 139     public static synchronized native LCMSProfile getProfileID(ICC_Profile profile);
 140 
 141     /* Helper method used from LCMSColorTransfrom */
 142     static long createTransform(
 143         LCMSProfile[] profiles, int renderType,
 144         int inFormatter, boolean isInIntPacked,
 145         int outFormatter, boolean isOutIntPacked,
 146         Object disposerRef)
 147     {
 148         long[] ptrs = new long[profiles.length];
 149 
 150         for (int i = 0; i < profiles.length; i++) {
 151             if (profiles[i] == null) throw new CMMException("Unknown profile ID");
 152 
 153             ptrs[i] = profiles[i].getLcmsPtr();
 154         }
 155 
 156         return createNativeTransform(ptrs, renderType, inFormatter,
 157                 isInIntPacked, outFormatter, isOutIntPacked, disposerRef);
 158     }
 159 
 160     private static native long createNativeTransform(
 161         long[] profileIDs, int renderType,
 162         int inFormatter, boolean isInIntPacked,
 163         int outFormatter, boolean isOutIntPacked,
 164         Object disposerRef);
 165 
 166     /**
 167      * Constructs ColorTransform object corresponding to an ICC_profile
 168      */
 169     public ColorTransform createTransform(ICC_Profile profile,
 170                                                        int renderType,
 171                                                        int transformType)
 172     {
 173         return new LCMSTransform(profile, renderType, renderType);
 174     }
 175 
 176     /**
 177      * Constructs an ColorTransform object from a list of ColorTransform
 178      * objects
 179      */
 180     public synchronized ColorTransform createTransform(
 181         ColorTransform[] transforms)
 182     {
 183         return new LCMSTransform(transforms);
 184     }
 185 
 186     /* methods invoked from LCMSTransform */
 187     public static native void colorConvert(LCMSTransform trans,
 188                                            LCMSImageLayout src,
 189                                            LCMSImageLayout dest);
 190 
 191     public static native void initLCMS(Class<?> Trans, Class<?> IL, Class<?> Pf);
 192 
 193     private LCMS() {};
 194 
 195     private static LCMS theLcms = null;
 196 
 197     static synchronized PCMM getModule() {
 198         if (theLcms != null) {
 199             return theLcms;
 200         }
 201 
 202         /* We need to load awt here because of usage trace and
 203          * disposer frameworks
 204          */
 205         jdk.internal.access.SharedSecrets.getJavaLangAccess().loadLibrary("awt");
 206         jdk.internal.access.SharedSecrets.getJavaLangAccess().loadLibrary("lcms");
 207 
 208         initLCMS(LCMSTransform.class, LCMSImageLayout.class, ICC_Profile.class);
 209 
 210         theLcms = new LCMS();
 211 
 212         return theLcms;
 213     }
 214 }