Open Bug 1163047 Opened 10 years ago Updated 2 years ago

CSS tokenizer and JS disagree about interpretation of "1.45"

Categories

(Core :: CSS Parsing and Computation, defect)

Other Branch
defect

Tracking

()

People

(Reporter: tromey, Unassigned)

Details

A devtools test caught the fact that the CSS tokenizer converts the token "1.45" to a number which is later printed as "1.4500000476837158". On the other hand, JS's parseFloat successfully round-trips "1.45" -> "1.45". (I didn't examine the underlying bits to see exactly how they differ in interpretation.) It would be handy for devtools if CSS and JS agreed on conversion of floating point values. I am wondering whether it would be possible to make nsCSSScanner::ScanNumber use js_strtod for floating-point numbers.
There's this: http://dev.w3.org/csswg/css-syntax/#convert-a-string-to-a-number But that doesn't actually specify how one would convert to a double. It just specifies the meaning in some abstract way -- so I think there's nothing in the standard preventing this. And in fact the JS way is better than what is done now, see the Clinger paper it is based on: http://www.cesura17.net/~will/Professional/Research/Papers/howtoread.pdf
> On the other hand, JS's parseFloat successfully round-trips "1.45" -> "1.45". Does it? 1.45 is not exactly representable, so what you're seeing there is that the double-to-string conversion is rounding to 1.45. In particular: parseFloat("1.45").toPrecision(21) "1.44999999999999995559" So that's issue number 1. But more importantly, issue number 2 is that the CSS scanner output is a _float_, not a double. Here's a simple C test program: float f = 1.45; double d = 1.45; printf("%.20f\n", f); printf("%.20f\n", d); and the output is: 1.45000004768371582031 1.44999999999999995559 which is exactly what you see (for the first one) and what JS outputs (for the second one). > And in fact the JS way is better than what is done now Better in what way? The only relevant metric is "faster", since they're equally accurate in this case: the CSS scanner does the conversion into a double, then converts that to float, so the difference between 0.97 units in the last mantissa bit and 0.5 units in the last mantissa bit (of the double) discussed in the paper you link to is not so relevant once the rounding to float happens. Going back to the main ask, though, getting JS and CSS to agree on conversion of floating point values is just impossible if JS is using doubles and CSS is using floats.
Also I see that nsCSSToken::mNumber is a float, not a double. So perhaps we'd want to change this to double for JS's sake, and let the double->float conversion happen in other users of the field.
Oh, and note that this is not exactly web-observable, since access to the value via CSSOM (whether specified style or computed style) will use AppendFloat, which does float-to-string conversion (as opposed to the float to double to string conversion that was done in comment 0, presumably), so things will get rounded to "1.45" correctly.
> Also I see that nsCSSToken::mNumber is a float, not a double. Yes, precisely. I guess we don't have too many nsCSSTokens around, so using a double there might be ok... Note that this will mean that in some cases what your JS-exposed tokenizer sees won't match what actually gets stored in Gecko, of course.
(In reply to Not doing reviews right now from comment #2) > But more importantly, issue number 2 is that the > CSS scanner output is a _float_, not a double. Yes, I realized this eventually. > Going back to the main ask, though, getting JS and CSS to agree on > conversion of floating point values is just impossible if JS is using > doubles and CSS is using floats. It seems you're correct and that all that matters is the float. That makes this much simpler then.
(In reply to Not doing reviews right now from comment #5) > > Also I see that nsCSSToken::mNumber is a float, not a double. > > Yes, precisely. > > I guess we don't have too many nsCSSTokens around, so using a double there > might be ok... Note that this will mean that in some cases what your > JS-exposed tokenizer sees won't match what actually gets stored in Gecko, of > course. Yeah, I am not sure if this matters. I will have to dig a bit more to find out, thanks for the note.
Is this actionable at all?
(In reply to Florian Bender from comment #8) > Is this actionable at all? It seems feasible to change the lexer to use doubles and expose those via CSSLexer to JS. This would fix the lexing case, but you could still see discrepancies. Devtools has since moved to a pure JS CSS lexer so this isn't a need there any more.
If devtools is not using this stuff, do we need it at all?
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.