Skip to content

JDK-8294090 : Aligns the CSS <rgb()> and <rgba()> function behaviours #16

@scientificware

Description

@scientificware

The purpose of this issue is to align the <rgb()> and <rgba()> function behaviours in CSS.java.

This is referenced in Java Bug Database as

This is tracked in JBS as

Related Pull Request

Aligns the <rgb()> and <rgba()> function behaviours in CSS.java, as described in :
CSS Color Module Level 4
W3C Candidate Recommendation Snapshot, 5 July 2022
4.1 The <Color> syntax
6.1. The RGB functions: rgb() and rgba()

  • In this recommendation there is no difference between the two function behaviours but this is not the case in the JDK present implementation.
  • Some other parts of the described syntax are not supported.
  • For example e-notation is not supported 5.3 Real Numbers: the <number> type

    ... a number is either an integer, or zero or more decimal digits followed by a dot (.) followed by one or more decimal digits; optionally, it can be concluded by the letter “e” or “E” followed by an integer indicating the base-ten exponent in scientific notation. ...

Status

  • This Enhancement Request is not yet accepted so it's internaly referenced in Java Bug Database as JI-9073933.

Basic test

  • In jshell type :
    import java.awt.Color;
    import javax.swing.text.html.StyleSheet;
    StyleSheet styleSheet = new StyleSheet();
    
  • First test :
    Expected result, a value not an Exception.
    styleSheet.stringToColor("rgba(12 23 17 50%)").getAlpha();
    |  Exception java.lang.IllegalArgumentException: Color parameter outside of expected range: Alpha
    |        at Color.testColorValueRange (Color.java:312)
    |        at Color.<init> (Color.java:397)
    |        at Color.<init> (Color.java:492)
    |        at CSS.parseRGBA (CSS.java:1475)
    |        at CSS.stringToColor (CSS.java:1404)
    |        at StyleSheet.stringToColor (StyleSheet.java:1029)
    |        at (#21:1)
    
  • Second test :
    Expected result, 240.
    styleSheet.stringToColor("rgb(12 23 17 / 0.94)").getAlpha();
    color ==> 255
    

Details :

  • Remind : (During the parsing process, before this method)
    • Leading and trailing white-spaces (according to Java) in the argument string were removed.
    • Inside () multiple white-space (according to Java) occurences are replaced by only one space character.
    • white-spaces (according to Java) between rgb or rgba and ( are removed.
  • If / is not present, <rgb> functions need 3 values. Not verified.
  • Else functions need 4 values. Not verified.
  • To avoid later incompatibilies, other cases should return null.
  • A value can be percent or number. But the range is not the same according the component.
    • r, g, b numbers in range 0 to 255 or percents in range 0% to 100%.
    • a number in range 0 to 1 or percent in range 0% to 100%.
  • none keyword not scaned.
  • The format of number used as value is not defined in the specification. Then implementations should use the previous implementation format.
  • Add number e-notation support (see above).

Consequences

  • <rgba> accepts most of these functionalities excepted % for alpha value. According comments above, implementation doesn't respect the alpha range and treates this component like r, g, b. It's a bug.
  • <rgb> doesn't accept alpha value. It's an enhancement.
  • none keyword not supported. It's an enhancement.
  • number used as value is Java float $s \times m \times 2^{e-150}$.
    • s is sign, 1 bit
    • m is magnitude 23 bits
    • e is exponent 8 bits

Syntax

rgb()
rgb( [<percentage> | none]{3} [ / [<alpha-value> | none] ]? )
rgb( [<number> | none]{3} [ / [<alpha-value> | none] ]? )
rgb( <percentage>#{3} , <alpha-value>? )
rgb( <number>#{3} , <alpha-value>? )
number:= [+|-]? [0...9]* [[. [0...9]*]]? [[e|E]! [0...9]*]?

Some tests

Value Ret. Val. Before PR Ret. Val. after PR
null null 🟢
# null null 🟢
#f java.awt.Color[r=0,g=0,b=15] + a=255 null
#f0 java.awt.Color[r=0,g=0,b=240] + a=255 null
#f0f java.awt.Color[r=255,g=0,b=255] + a=255 java.awt.Color[r=255,g=0,b=255] + a=255 🟢
#f0f1 java.awt.Color[r=0,g=240,b=241] + a=255 java.awt.Color[r=255,g=0,b=255] + a=17
#f0f10 java.awt.Color[r=15,g=15,b=16] + a=255 null
#f0f109 java.awt.Color[r=240,g=241,b=9] + a=255 java.awt.Color[r=240,g=241,b=9] + a=255 🟢
#f0f1092 java.awt.Color[r=240,g=241,b=9] + a=255 null
#f0f10928 java.awt.Color[r=240,g=241,b=9] + a=255 java.awt.Color[r=240,g=241,b=153] + a=40
f0f10928 null java.awt.Color[r=240,g=241,b=9] + a=40
#f0f109289 java.awt.Color[r=240,g=241,b=9] + a=255 null
f0f109289 null null 🟢
ppabcdef null null 🟢
b52k null null 🟢
#ppabcdef null null 🟢
#b52k null null 🟢
#ffffffff java.awt.Color[r=255,g=255,b=255] + a=255 java.awt.Color[r=255,g=255,b=255] + a=255 🟢
ffffffff null java.awt.Color[r=255,g=255,b=255] + a=255
#ffffff java.awt.Color[r=255,g=255,b=255] + a=255 java.awt.Color[r=255,g=255,b=255] + a=255 🟢
ffffff java.awt.Color[r=255,g=255,b=255] + a=255 java.awt.Color[r=255,g=255,b=255] + a=255 🟢
Value stringToColr Ret. Val. Expected Val.
rgb(12 24 200) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(-1 24 200%) java.awt.Color[r=0,g=24,b=255] + a=255 rgba(0 24 255 1.0) 🟢 rgba(0 24 255 1.0)
rgb(300 24 28) java.awt.Color[r=255,g=24,b=28] + a=255 rgba(255 24 28 1.0) 🟢 rgba(255 24 28 1.0)
rgb(12 24 200 / 82%) java.awt.Color[r=12,g=24,b=200] + a=209 rgba(12 24 200 0.82) 🟢 rgba(12 24 200 0.82)
rgb(12 24 200 / 0.82) java.awt.Color[r=12,g=24,b=200] + a=209 rgba(12 24 200 0.82) 🟢 rgba(12 24 200 0.82)
rgb(12 24 200 / -210) java.awt.Color[r=12,g=24,b=200] + a=0 rgba(12 24 200 0.0) 🟢 rgba(12 24 200 0.0)
rgb(12, 24, 200) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(12, 24, 200, 210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(12, 24, 200 , 210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(12 , 24 , 200 , 210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb( 12 , 24 , 200 , 210 ) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(12 ,24, 200 ,210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(12,24,200,210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(15% 60% 49%) java.awt.Color[r=38,g=153,b=125] + a=255 rgba(38 153 125 1.0) 🟢 rgba(38 153 125 1.0)
rgb(15% 60% 49% / 82%) java.awt.Color[r=38,g=153,b=125] + a=209 rgba(38 153 125 0.82) 🟢 rgba(38 153 125 0.82)
rgb(15%, 60%, 49% / 82%) java.awt.Color[r=38,g=153,b=125] + a=209 rgba(38 153 125 0.82) 🟢 rgba(38 153 125 0.82)
rgb(0.14 60% 52.3 / 0.98) java.awt.Color[r=0,g=153,b=52] + a=250 rgba(0 153 52 0.98) 🟢 rgba(0 153 52 0.98)
rgb(none none none) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0)
rgb(none none none / none) java.awt.Color[r=0,g=0,b=0] + a=0 rgba(0 0 0 0.0) 🟢 rgba(0 0 0 0.0)
rgb(none none none / none) java.awt.Color[r=0,g=0,b=0] + a=0 rgba(0 0 0 0.0) 🟢 rgba(0 0 0 0.0)
rgb(none none 30) java.awt.Color[r=0,g=0,b=30] + a=255 rgba(0 0 30 1.0) 🟢 rgba(0 0 30 1.0)
rgb(none 20 none) java.awt.Color[r=0,g=20,b=0] + a=255 rgba(0 20 0 1.0) 🟢 rgba(0 20 0 1.0)
rgb(10 none none) java.awt.Color[r=10,g=0,b=0] + a=255 rgba(10 0 0 1.0) 🟢 rgba(10 0 0 1.0)
rgb(none none none) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0)
rgb(10 50 13% / 50%) java.awt.Color[r=10,g=50,b=33] + a=128 rgba(10 50 33 0.5) 🟢 rgba(10 50 33 0.5)
rgb(10 50 13% // 50%) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0)
rgb(10 50,, 13% // 50%) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0)
rgb(10 50 ,, 13% // 50%) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0)
rgb(1.2e1 0.24e2 2e2) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
rgb(1200e-2 2400e-2 200000e-3) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0)
Value stringToColr Ret. Val. Exp. Val. (R, G, B) comp. Valid Exp. Val. (R, G, B) comp. Valid
rgb(12 24 200) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(12 24 200%) java.awt.Color[r=12,g=24,b=255] + a=255 rgba(12 24 255 1.0) 🟢 rgba(12 24 255 1.0) 🟢
rgb(-1 24 200%) java.awt.Color[r=0,g=24,b=255] + a=255 rgba(0 24 255 1.0) 🟢 rgba(0 24 255 1.0) 🟢
rgb(300 24 28) java.awt.Color[r=255,g=24,b=28] + a=255 rgba(255 24 28 1.0) 🟢 rgba(255 24 28 1.0) 🟢
rgb(12 24 200 / 82%) java.awt.Color[r=12,g=24,b=200] + a=209 rgba(12 24 200 0.82) 🟢 rgba(12 24 200 0.82) 🟢
rgb(12 24 200 / 0.82) java.awt.Color[r=12,g=24,b=200] + a=209 rgba(12 24 200 0.82) 🟢 rgba(12 24 200 0.82) 🟢
rgb(12 24 200 / -210) java.awt.Color[r=12,g=24,b=200] + a=0 rgba(12 24 200 0.0) 🟢 rgba(12 24 200 0.0) 🟢
rgb(12, 24, 200) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(12, 24, 200, 210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(12, 24, 200 , 210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(12 , 24 , 200 , 210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb( 12 , 24 , 200 , 210 ) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(12 ,24, 200 ,210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(12,24,200,210) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(15% 60% 49%) java.awt.Color[r=38,g=153,b=125] + a=255 rgba(38 153 125 1.0) 🟢 rgba(38 153 125 1.0) 🟢
rgb(15% 60% 49% / 82%) java.awt.Color[r=38,g=153,b=125] + a=209 rgba(38 153 125 0.82) 🟢 rgba(38 153 125 0.82) 🟢
rgb(15%, 60%, 49% / 82%) java.awt.Color[r=38,g=153,b=125] + a=209 rgba(38 153 125 0.82) 🟢 rgba(38 153 125 0.82) 🟢
rgb(0.14 60% 52.3 / 0.98) java.awt.Color[r=0,g=153,b=52] + a=250 rgba(0 153 52 0.98) 🟢 rgba(0 153 52 0.98) 🟢
rgb(none none none) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0) 🟢
rgb(none none none / none) java.awt.Color[r=0,g=0,b=0] + a=0 rgba(0 0 0 0.0) 🟢 rgba(0 0 0 0.0) 🟢
rgb(none none none/none) java.awt.Color[r=0,g=0,b=0] + a=0 rgba(0 0 0 0.0) 🟢 rgba(0 0 0 0.0) 🟢
rgb(none none 30) java.awt.Color[r=0,g=0,b=30] + a=255 rgba(0 0 30 1.0) 🟢 rgba(0 0 30 1.0) 🟢
rgb(none 20 none) java.awt.Color[r=0,g=20,b=0] + a=255 rgba(0 20 0 1.0) 🟢 rgba(0 20 0 1.0) 🟢
rgb(10 none none) java.awt.Color[r=10,g=0,b=0] + a=255 rgba(10 0 0 1.0) 🟢 rgba(10 0 0 1.0) 🟢
rgb(none none none) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0) 🟢
rgb(10 50 13% / 50%) java.awt.Color[r=10,g=50,b=33] + a=128 rgba(10 50 33 0.5) 🟢 rgba(10 50 33 0.5) 🟢
rgb(10 50 13% // 50%) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0) 🟢
rgb(10 50,, 13% // 50%) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0) 🟢
rgb(10 50 ,, 13% // 50%) java.awt.Color[r=0,g=0,b=0] + a=255 rgba(0 0 0 1.0) 🟢 rgba(0 0 0 1.0) 🟢
rgb(1.2e1 0.24e2 2e2) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(1200e-2 2400e-2 200000e-3) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢
rgb(120560.64646464632469823160676064670646798706406464098706464097970906464067e-4 2400e-2 200000e-3) java.awt.Color[r=12,g=24,b=200] + a=255 rgba(12 24 200 1.0) 🟢 rgba(12 24 200 1.0) 🟢

About performances

  • Performance test available. What is tested :
    • 1 000 occurences of :
      • a set of 1 650 valid color rgb rgba notations, equi-distributed (Not Real WWW).
      • and wrong color notations except alpha percent values.
  • Enhancements must be at least without performance cost.
Run Nb Tests Befor PR (ms) First Ext Impl. (ms) V1 Ext Impl. (ms) V1 Ext Impl. optimised (ms) V3 Ext Impl. (ms)
<rgb> alpha support ✔️ ✔️ ✔️ ✔️
<rgb> none support ✔️ ✔️ ✔️ ✔️
Number Gen Ext Impl. ✔️ ✔️ ✔️
<rgb> base-ten floating-point notation support ✔️
1 1 650 000 249 342 222 157 166
2 1 650 000 243 342 221 162
3 1 650 000 239 340 222 167
4 1 650 000 258 340 223 166
5 1 650 000 243 339 217 165

✔️

Metadata

Metadata

Labels

EnhancementNew feature or requestFixedFixed issue.ReporterReported this Issue to Java Bug DataBaseWIPWork In Progress

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions