JDK-4895924 : Strings in format #rgb not handled by Color.decode() (affects CSS / Swing)
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.1_06,1.4.1,1.4.1_03,1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux,windows_2000
  • CPU: x86
  • Submitted: 2003-07-24
  • Updated: 2022-09-11
  • Resolved: 2019-02-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 13
13 b10Resolved
Related Reports
Duplicate :  
Relates :  
Description

Name: jk109818			Date: 07/24/2003


FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)


FULL OPERATING SYSTEM VERSION :
Linux jupiter 2.4.19-4GB #1 Fri Sep 13 13:19:15 UTC 2002
i686 unknown


A DESCRIPTION OF THE PROBLEM :
I wrote a simple web browser using the JEditorPane class.
When I viewed some sites, I detected that JEditorPane
displayed wrong colors. When I took a look at the style
sheets, I detected that the colors were given in three
instead  of six sedecimal digits, like
"background-color:#eee";, which is completely legal CSS and
should be expanded to #eeeeee; on 24 bit color systems.
Java does not expand #eee; to #eeeeee; but instead to
#000eee; which of course produces the wrong colors.

I believe that Swing simply uses AWT's
Color.decode(String)-Method to create the required Color object.

I've found out that Color.decode() doesn't handle
3-digit-color values as they may be used in CSS.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Write a browser (source below)
2. Run it
3. load the page (source below)

Or:
1. Create a Color-Object.
2. Print it out.
3. Look at it's RGB values

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected result: light light gray background
Actual result: blue background

Interpretation:
Instead of expanding #eee to #eeeeee to generate the color
value, #eee is interpreted as #000eee;

Or:

System.out.println(Color.decode("#eee"));
expected result: java.awt.Color[r=238,g=238,b=238]
actual result: java.awt.Color[r=0,g=14,b=238]


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Source code of Java Browser:

import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
import javax.swing.text.html.HTMLDocument;

public class Browser extends JFrame implements HyperlinkListener {

    public static final String revision = "$Revision: 1.7 $";

    private static Browser b;

    public static void main(final String[] args) throws IOException,
MalformedURLException {
        if ("1.4.0".compareTo(System.getProperty("java.version")) >= 0) {
            JDialog.setDefaultLookAndFeelDecorated(true);
            JFrame.setDefaultLookAndFeelDecorated(true);
            Toolkit.getDefaultToolkit().setDynamicLayout(true);
        }
        if (args.length != 0) {
            b = new Browser(args[0]);
        } else {
            b = new Browser();
        }
        // System.out.println(Toolkit.getDefaultToolkit().getScreenSize());
        b.setSize(Toolkit.getDefaultToolkit().getScreenSize());
        b.setVisible(true);
        b.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        b.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                b.dispose();
                b = null;
            }
        });
    }

    private JEditorPane browser;

    public Browser() throws IOException, MalformedURLException {
        this("file:///usr/lib/jax/sun/j2sdkse/latest/docs/index.html");
    }

    public Browser(final String url) throws IOException, MalformedURLException {
        super(url);
        browser = new JEditorPane(new URL(url));
        browser.setEditable(false);
        browser.addHyperlinkListener(this);
        JScrollPane scroll = new JScrollPane(browser);
        getContentPane().add(scroll);
    }

    public void hyperlinkUpdate(final HyperlinkEvent e) {
        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
            JEditorPane pane = (JEditorPane) e.getSource();
            if (e instanceof HTMLFrameHyperlinkEvent) {
                HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
                HTMLDocument doc = (HTMLDocument) pane.getDocument();
                doc.processHTMLFrameHyperlinkEvent(evt);
            } else {
                try {
                    pane.setPage(e.getURL());
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        }
    }
}


Source code of html / css file demonstrating the problem:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>Problem</title>
        <style type="text/css">
            body {
                background-color:#eee;
            }
        </style>
    </head>
    <body>
        <h1>Text</h1>
    </body>
</html>


Or source code demonstrating the problem with class Color:
import java.awt.Color;

public class ColorTest {
    public static void main(String[] args) {
        System.out.println("The following two should be equal:");
        System.out.println(Color.decode("#eeeeee"));
        System.out.println(Color.decode("#eee"));
        assert
            Color.decode("#eee").equals(Color.decode("#eeeeee")) :
            "3 hex-digit Colors must be interpreted the same way as their
corresponding 6 hex-digit Colors";
    }
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
There is no workaround for this possible, as one can't
change other site's stylesheets.


I think the bug can be fixed by changing
java.awt.Color.decode() to: (untested)

    /**
     * Converts a <code>String</code> to an integer and
returns the
     * specified opaque <code>Color</code>. This method
handles string
     * formats that are used to represent octal and
hexidecimal numbers.
     * @param      nm a <code>String</code> that represents
     *                            an opaque color as a
24-bit integer
     *                            or as a 12-bit sedecimal
integer #rgb
     * @return     the new <code>Color</code> object.
     * @see        java.lang.Integer#decode
     * @exception  NumberFormatException  if the specified
string cannot
     *                      be interpreted as a decimal,
     *                      octal, or hexidecimal integer.
     * @since      JDK1.1
     */
    public static Color decode(final String nm) throws
NumberFormatException {
        Integer intval;
        if (nm.startsWith("#") && nm.length() == 4) {
            intval = Integer.decode("#" + nm.charAt(1) +
nm.charAt(1) + nm.charAt(2) + nm.charAt(2) + nm.charAt(3) +
nm.charAt(3));
        } else {
            intval = Integer.decode(nm);
        }
        int i = intval.intValue();
        return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF,
i & 0xFF);
    }
(Incident Review ID: 179135) 
======================================================================

Comments
URL: http://hg.openjdk.java.net/jdk/jdk/rev/a986e16d8449 User: psadhukhan Date: 2019-02-27 09:16:08 +0000
27-02-2019

URL: http://hg.openjdk.java.net/jdk/client/rev/a986e16d8449 User: psadhukhan Date: 2019-02-26 05:38:27 +0000
26-02-2019

EVALUATION Color.java belongs to 2D. ###@###.### 2003-07-24 Color.decode() specifies that it converts a string to an integer. It is using Integer.decode() to perform the conversion. It does not specify that the decoded string is in a format that is understood to be a CSS string. This means that Swing cannot count on just being able to pass an HTML CSS string into Color.decode and get the correct interpretation. ###@###.### 2003-07-24
24-07-2003