-
Notifications
You must be signed in to change notification settings - Fork 563
8377427: Reduce substring allocations in Color.web(String, double) #2069
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
base: master
Are you sure you want to change the base?
Conversation
|
👋 Welcome back mstrauss! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
Webrevs
|
|
+1 |
|
|
||
| if (colorString.regionMatches(true, 0, "#", 0, 1)) { | ||
| offset = 1; | ||
| } else if (colorString.regionMatches(true, 0, "0x", 0, 2)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interestingly, while the code (both old and new) ignores case, the javadoc says nothing about case sensitivity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does say that it parses a CSS color string, and CSS is case-insensitive.
| int start = off; | ||
| int limit = end; | ||
|
|
||
| while (start < limit && Character.isWhitespace(color.charAt(start))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this change is not equivalent: the trim() function (used before) removes leading and trailing "spaces" which are defined as space is defined as any character whose codepoint is less than or equal to 'U+0020' (the space character).
Character.isWhitespace() is different:
hex| trim| isWhitespace
0x00 W -
0x01 W -
0x02 W -
0x03 W -
0x04 W -
0x05 W -
0x06 W -
0x07 W -
0x08 W -
0x09 W W
0x0a W W
0x0b W W
0x0c W W
0x0d W W
0x0e W -
0x0f W -
0x10 W -
0x11 W -
0x12 W -
0x13 W -
0x14 W -
0x15 W -
0x16 W -
0x17 W -
0x18 W -
0x19 W -
0x1a W -
0x1b W -
0x1c W W
0x1d W W
0x1e W W
0x1f W W
0x20 W W
see https://github.com/andy-goryachev-oracle/Test/blob/main/test/goryachev/research/TestWhitespace.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While that's true, I think it is irrelevant. Color.web() is not specified to just skip over non-whitespace control characters inside of a color function, and it is not prudent to assume that a string parsing function would silently skip over non-whitespace control characters by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am pointing out a non-zero chance of regression, for instance when this method is used to parse an external poorly formatted file with no sanitizing.
I do agree that this change is probably fine though.
Use of Color.web("rgba(2, 2, 1, 0.25e2f)") |
You're right, the specification of Not every string that is parsed by |
andy-goryachev-oracle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JavaFX CSS spec states (under ):
Real numbers and integers are specified in decimal notation only. ... A <number> can either be an <integer>, or it can be zero or more digits followed by a dot (.) followed by one or more digits. Both integers and real numbers may be preceded by a "-" or "+" to indicate the sign. -0 is equivalent to 0 and is not a negative number.
[+|-]? [[0-9]+|[0-9]*"."[0-9]+]
it looks to me like exponential notation should not be supported.
| long rawBits = Double.doubleToRawLongBits(v); | ||
| return rawBits >= 0 ? rawBits : (0x8000_0000_0000_0000L - rawBits); | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing newline
| assertNumberFormatException(" 1"); | ||
| assertNumberFormatException("1 "); | ||
| assertNumberFormatException("xx1e2yy", 2, 6); // slice is "1e2y" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add another test for malformed numbers such as ++0, 1e--2, etc.?
|
|
||
| @Test | ||
| public void parseIntegerAndSignedInteger() { | ||
| assertEquals(0.0, parseDouble("0"), 0.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JavaFX CSS spec also states
-0 is equivalent to 0 and is not a negative number.
How should we test this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the JVM, -0 == 0. It seems to me that this sentence just spells it out, doesn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. The new parser parses "-0.0" as -0.0, and while (-0.0 == 0.0), the result of some other operations is different (1/-0.0 = -Infinity).
Does it constitutes a regression risk for applications?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CssNumberParser parses "-0" correctly as -0, just like Double.parseDouble() currently does. The existing code in Color is unchanged.
In the interest of not being different just for the sake of it, we should probably change this specification and use the W3C definition of a number everywhere. Not terribly important (no one uses E notation anyway), but better be consistent. |
|
Mandatory disclaimer: W3C is not a real standard. I am not sure if we want to change the CSS spec to allow scientific notation in all the s, I don't even sure we want to add this support in |
|
I must admit I don't know how much changes in |
| r = Integer.parseInt(color.substring(0, 1), 16); | ||
| g = Integer.parseInt(color.substring(1, 2), 16); | ||
| b = Integer.parseInt(color.substring(2, 3), 16); | ||
| r = Integer.parseInt(colorString, offset, offset + 1, 16); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would a switch statement be better in this case (e.g. case when len == 1)?
5.8 billion web browser installations disagree. What fraction of a fraction of a percent of this number is JavaFX again? W3C's baseline compatibility standard is as good as any standard can possibly be. There are no other CSS specifications of any significance whatsoever.
Right now, the situation is a bit inconsistent:
JavaFX contradicts its own specification, but the specification is (and has always been) wrong anyway. |
|
it's not a real standard in a sense that it is an attempt to write a spec for something that every browser manufacturer want to change to make their browser "better". maybe the situation changed recently, I don't know. But I do agree with you - the majority of developers are familiar with it, so it might make sense to adapt in some cases (while keeping in mind possible regressions).
This is hilarious and concerning at the same time. I wonder whether we need to update the javadoc / create a CSR since we are changing the behavior. What do you think? |
Color.web(string, double) parses a color string by creating substrings of the input. These string allocations can be removed.
There are no new tests for the
Colorclass, since the existing tests already cover all relevant code paths./reviewers 2
Progress
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/2069/head:pull/2069$ git checkout pull/2069Update a local copy of the PR:
$ git checkout pull/2069$ git pull https://git.openjdk.org/jfx.git pull/2069/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 2069View PR using the GUI difftool:
$ git pr show -t 2069Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/2069.diff
Using Webrev
Link to Webrev Comment