Skip to content

8359380: Rework deferral profile logic after JDK-8346465 #26179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 24 additions & 39 deletions src/java.desktop/share/classes/java/awt/color/ICC_Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@
import java.util.StringTokenizer;

import sun.awt.AWTAccessor;
import sun.java2d.cmm.BuiltinProfileInfo;
import sun.java2d.cmm.CMSManager;
import sun.java2d.cmm.PCMM;
import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileDataVerifier;
import sun.java2d.cmm.ProfileDeferralInfo;

import static sun.java2d.cmm.ProfileDataVerifier.HEADER_SIZE;

Expand Down Expand Up @@ -102,20 +102,11 @@ public sealed class ICC_Profile implements Serializable
private transient volatile Profile cmmProfile;

/**
* Stores some information about {@code ICC_Profile} without causing a
* deferred profile to be loaded. Note that we can defer the loading of
* standard profiles only. If this field is null, then {@link #cmmProfile}
* should be used to access profile information.
* Stores information about a built-in profile without triggering profile
* loading. If this field is null, {@link #cmmProfile} should be used to
* access profile data. If not null, the profile is considered immutable.
*/
private transient volatile ProfileDeferralInfo deferralInfo;


/**
* Set to {@code true} for {@code BuiltInProfile}, {@code false} otherwise.
* This flag is used in {@link #setData(int, byte[])} to prevent modifying
* built-in profiles.
*/
private final transient boolean builtIn;
private transient final BuiltinProfileInfo builtInInfo;

/**
* The lazy registry of singleton profile objects for specific built-in
Expand All @@ -124,22 +115,22 @@ public sealed class ICC_Profile implements Serializable
*/
private interface BuiltInProfile {
/*
* ProfileDeferralInfo is used for built-in profile creation only,
* BuiltinProfileInfo is used for built-in profile creation only,
* and all built-in profiles should be constructed using it.
*/
ICC_Profile SRGB = new ICC_ProfileRGB(new ProfileDeferralInfo(
ICC_Profile SRGB = new ICC_ProfileRGB(new BuiltinProfileInfo(
"sRGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY));

ICC_Profile LRGB = new ICC_ProfileRGB(new ProfileDeferralInfo(
ICC_Profile LRGB = new ICC_ProfileRGB(new BuiltinProfileInfo(
"LINEAR_RGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY));

ICC_Profile XYZ = new ICC_Profile(new ProfileDeferralInfo(
ICC_Profile XYZ = new ICC_Profile(new BuiltinProfileInfo(
"CIEXYZ.pf", ColorSpace.TYPE_XYZ, 3, CLASS_ABSTRACT));

ICC_Profile PYCC = new ICC_Profile(new ProfileDeferralInfo(
ICC_Profile PYCC = new ICC_Profile(new BuiltinProfileInfo(
"PYCC.pf", ColorSpace.TYPE_3CLR, 3, CLASS_COLORSPACECONVERSION));

ICC_Profile GRAY = new ICC_ProfileGray(new ProfileDeferralInfo(
ICC_Profile GRAY = new ICC_ProfileGray(new BuiltinProfileInfo(
"GRAY.pf", ColorSpace.TYPE_GRAY, 1, CLASS_DISPLAY));
}

Expand Down Expand Up @@ -771,20 +762,19 @@ private interface BuiltInProfile {
*/
ICC_Profile(Profile p) {
cmmProfile = p;
builtIn = false;
builtInInfo = null;
}

/**
* Constructs an {@code ICC_Profile} object whose loading will be deferred.
* The ID will be 0 until the profile is loaded.
*
* <p>
* Note: {@code ProfileDeferralInfo} is used for built-in profile
* Note: {@code BuiltinProfileInfo} is used for built-in profile
* creation only, and all built-in profiles should be constructed using it.
*/
ICC_Profile(ProfileDeferralInfo pdi) {
deferralInfo = pdi;
builtIn = true;
ICC_Profile(BuiltinProfileInfo pdi) {
builtInInfo = pdi;
}

/**
Expand Down Expand Up @@ -934,16 +924,14 @@ private Profile cmmProfile() {
if (cmmProfile != null) {
return cmmProfile;
}
var is = getStandardProfileInputStream(deferralInfo.filename);
var is = getStandardProfileInputStream(builtInInfo.filename);
if (is == null) {
return null;
}
try (is) {
byte[] data = getProfileDataFromStream(is);
if (data != null) {
p = cmmProfile = CMSManager.getModule().loadProfile(data);
// from now we cannot use the deferred value, drop it
deferralInfo = null;
}
} catch (CMMException | IOException ignore) {
}
Expand Down Expand Up @@ -975,9 +963,8 @@ public int getMinorVersion() {
* @return one of the predefined profile class constants
*/
public int getProfileClass() {
ProfileDeferralInfo info = deferralInfo;
if (info != null) {
return info.profileClass;
if (builtInInfo != null) {
return builtInInfo.profileClass;
}
byte[] theHeader = getData(cmmProfile(), icSigHead);
return getProfileClass(theHeader);
Expand Down Expand Up @@ -1012,9 +999,8 @@ private static int getProfileClass(byte[] data) {
* {@code ColorSpace} class
*/
public int getColorSpaceType() {
ProfileDeferralInfo info = deferralInfo;
if (info != null) {
return info.colorSpaceType;
if (builtInInfo != null) {
return builtInInfo.colorSpaceType;
}
byte[] theHeader = getData(cmmProfile(), icSigHead);
return getColorSpaceType(theHeader);
Expand Down Expand Up @@ -1160,8 +1146,8 @@ static byte[] getData(Profile p, int tagSignature) {
* @see ColorSpace
*/
public void setData(int tagSignature, byte[] tagData) {
if (builtIn) {
throw new IllegalArgumentException("Built-in profile cannot be modified");
if (builtInInfo != null) {
throw new IllegalArgumentException("Can't modify built-in profile");
}

if (tagSignature == ICC_Profile.icSigHead) {
Expand Down Expand Up @@ -1205,9 +1191,8 @@ private static void checkRenderingIntent(byte[] data) {
* @throws ProfileDataException if color space is in the profile is invalid
*/
public int getNumComponents() {
ProfileDeferralInfo info = deferralInfo;
if (info != null) {
return info.numComponents;
if (builtInInfo != null) {
return builtInInfo.numComponents;
}
byte[] theHeader = getData(cmmProfile(), icSigHead);
int theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@

import java.io.Serial;

import sun.java2d.cmm.BuiltinProfileInfo;
import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileDeferralInfo;

/**
* The {@code ICC_ProfileGray} class is a subclass of the {@code ICC_Profile}
Expand Down Expand Up @@ -87,9 +87,9 @@ public final class ICC_ProfileGray extends ICC_Profile {

/**
* Constructs a new {@code ICC_ProfileGray} from a
* {@code ProfileDeferralInfo} object.
* {@code BuiltinProfileInfo} object.
*/
ICC_ProfileGray(ProfileDeferralInfo pdi) {
ICC_ProfileGray(BuiltinProfileInfo pdi) {
super(pdi);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@

import java.io.Serial;

import sun.java2d.cmm.BuiltinProfileInfo;
import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileDeferralInfo;

/**
* The {@code ICC_ProfileRGB} class is a subclass of the {@code ICC_Profile}
Expand Down Expand Up @@ -122,11 +122,11 @@ public final class ICC_ProfileRGB extends ICC_Profile {

/**
* Constructs a new {@code ICC_ProfileRGB} from a
* {@code ProfileDeferralInfo} object.
* {@code BuiltinProfileInfo} object.
*
* @param pdi
*/
ICC_ProfileRGB(ProfileDeferralInfo pdi) {
ICC_ProfileRGB(BuiltinProfileInfo pdi) {
super(pdi);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, 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
Expand All @@ -26,15 +26,15 @@
package sun.java2d.cmm;

/**
* A class to pass information about a profile to be loaded from a file to the
* static getInstance(int cspace) method of ICC_Profile. Loading of the profile
* data and initialization of the CMM is to be deferred as long as possible.
* Stores information about a built-in profile used by
* ICC_Profile.getInstance(int cspace) to defer the loading of profile data and
* CMM initialization. Since built-in profiles are immutable, this information
* is always valid.
*/
public final class ProfileDeferralInfo {
public final class BuiltinProfileInfo {

/**
* Need to have this info for ICC_ColorSpace without causing a deferred
* profile to be loaded.
* Used by ICC_ColorSpace without triggering built-in profile loading.
*/
public final int colorSpaceType, numComponents, profileClass;

Expand All @@ -43,7 +43,7 @@ public final class ProfileDeferralInfo {
*/
public final String filename;

public ProfileDeferralInfo(String fn, int type, int ncomp, int pclass) {
public BuiltinProfileInfo(String fn, int type, int ncomp, int pclass) {
filename = fn;
colorSpaceType = type;
numComponents = ncomp;
Expand Down
38 changes: 22 additions & 16 deletions test/jdk/java/awt/color/CheckDefaultProperties.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
Expand Down Expand Up @@ -34,8 +34,9 @@

/**
* @test
* @bug 8256321
* @summary Verifies profile properties are the same before/after activation
* @bug 8256321 8359380
* @summary Verifies built-in profile properties are the same before and after
* activation and in copies of built-in profiles
*/
public final class CheckDefaultProperties {

Expand All @@ -46,21 +47,26 @@ public static void main(String[] args) {
ICC_Profile lrgb = ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB);
ICC_Profile pycc = ICC_Profile.getInstance(ColorSpace.CS_PYCC);

// check default values, before profile activation
test(srgb, TYPE_RGB, 3, CLASS_DISPLAY);
test(gray, TYPE_GRAY, 1, CLASS_DISPLAY);
test(xyz, TYPE_XYZ, 3, CLASS_ABSTRACT);
test(lrgb, TYPE_RGB, 3, CLASS_DISPLAY);
test(pycc, TYPE_3CLR, 3, CLASS_COLORSPACECONVERSION);
// checks default values before built-in profiles are activated
test(srgb, gray, xyz, lrgb, pycc);

// activates built-in profiles and creates copies
ICC_Profile srgbCopy = ICC_Profile.getInstance(srgb.getData());
ICC_Profile grayCopy = ICC_Profile.getInstance(gray.getData());
ICC_Profile xyzCopy = ICC_Profile.getInstance(xyz.getData());
ICC_Profile lrgbCopy = ICC_Profile.getInstance(lrgb.getData());
ICC_Profile pyccCopy = ICC_Profile.getInstance(pycc.getData());

// activate profiles
srgb.getData();
gray.getData();
xyz.getData();
lrgb.getData();
pycc.getData();
// checks default values after profile activation
test(srgb, gray, xyz, lrgb, pycc);

// checks default values in copies of the built-in profiles
test(srgbCopy, grayCopy, xyzCopy, lrgbCopy, pyccCopy);
}

// check default values, after profile activation
private static void test(ICC_Profile srgb, ICC_Profile gray,
ICC_Profile xyz, ICC_Profile lrgb,
ICC_Profile pycc) {
test(srgb, TYPE_RGB, 3, CLASS_DISPLAY);
test(gray, TYPE_GRAY, 1, CLASS_DISPLAY);
test(xyz, TYPE_XYZ, 3, CLASS_ABSTRACT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
public class BuiltInProfileCheck {
private static final int HEADER_TAG = ICC_Profile.icSigHead;
private static final int INDEX = ICC_Profile.icHdrDeviceClass;
private static final String EXCEPTION_MSG = "Built-in profile cannot be modified";
private static final String EXCEPTION_MSG = "Can't modify built-in profile";
/**
* {@link #prepareTestProfile(String, boolean, int)}
* stores the profile to test in testProfile.
Expand Down