Open towerofnix opened 4 months ago
This was kind of an obvious thing for me to overlook initially, but -Infinity + Infinity
and Infinity + -Infinity
are both NaN, which makes corresponding edges always be NaN: you're getting the minimum/maximum of ±Infinity and NaN, which is always NaN, by spec.
planeBottomTopLeftRight
is the only remaining "surprising" case (new DOMRect(Infinity, -Infinity, Infinity, -Infinity)
), but here we're summing like signs, (x: Infinity) + (width: Infinity) and (y: -Infinity) + (height: -Infinity), so no NaN is involved and normal minimum/maximum logic applies. This is also, uh, an error in my chart, since really this just means "the top-right quadrant relative to (Infinity, -Infinity)" — the correct plane definition here would be new DOMRect(-Infinity, Infinity, Infinity, -Infinity)
.
I don't believe it's possible to represent a plane with DOMRect - on a practical level because those involve opposing infinities (so bounds always perform min/max with NaN), and on a theoretical level because planes don't fundamentally express an origin, they're just the dimension space. DOMRect is always in terms of an origin point (a DOMRect could be described as "the positive or negative width/height extending away from an origin x/y").
Document conventions includes the following description for NaN-safe minimum and NaN-safe maximum:
This was introduced in #395 following discussion in #222 and mailing lists (quoted in the latter issue).
Although Infinity is explicitly mentioned in the (quoted) mailing list, it isn't in the spec or issue discussion.
So I just wanted to ask, is the behavior for Infinity currently defined? At the moment we're using the verb "if ... is NaN" to specify the special behavior ("the NaN-safe minimum … is NaN"), and the default behavior is otherwise only "the minimum of" the list of terms. I don't see definitions or references for what "is NaN" and "the minimum of" mean within this spec, which seems like potentially undefined behavior to me.
Test script to observe behavior of infinity on various edges and areas:
```js rects = { infinityTowardsRight: new DOMRect(0, 0, Infinity, 0), infinityTowardsLeft: new DOMRect(0, 0, -Infinity, 0), infinityAtRight: new DOMRect(Infinity, 0, 0, 0), infinityAtLeft: new DOMRect(-Infinity, 0, 0, 0), infinityLeftToRight: new DOMRect(-Infinity, 0, Infinity, 0), infinityRightToLeft: new DOMRect(Infinity, 0, -Infinity, 0), infinityTowardsBottom: new DOMRect(0, 0, 0, Infinity), infinityTowardsTop: new DOMRect(0, 0, 0, -Infinity), infinityAtBottom: new DOMRect(0, Infinity, 0, 0), infinityAtTop: new DOMRect(0, -Infinity, 0, 0), infinityTopToBottom: new DOMRect(0, -Infinity, 0, Infinity), infinityBottomToTop: new DOMRect(0, Infinity, 0, -Infinity), bottomRightQuadrant: new DOMRect(0, 0, Infinity, Infinity), bottomLeftQuadrant: new DOMRect(0, 0, -Infinity, Infinity), topRightQuadrant: new DOMRect(0, 0, Infinity, -Infinity), topLeftQuadrant: new DOMRect(0, 0, -Infinity, Infinity), planeTopBottomLeftRight: new DOMRect(-Infinity, -Infinity, Infinity, Infinity), planeTopBottomRightLeft: new DOMRect(Infinity, -Infinity, -Infinity, Infinity), planeBottomTopLeftRight: new DOMRect(Infinity, -Infinity, Infinity, -Infinity), planeBottomTopRightLeft: new DOMRect(Infinity, Infinity, -Infinity, -Infinity), }; props = ['x', 'y', 'width', 'height', 'left', 'right', 'top', 'bottom']; console.log(`Rectangle,` + props.join(',')); for (const [name, rect] of Object.entries(rects)) { console.log(`${name},${props.map(p => rect[p]).join(',')}`); } ```Results are conveniently identical in Safari 17.4, Firefox 123, Chrome 122:
| Rectangle | x | y | width | height | left | right | top | bottom | |-------------------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------| | infinityTowardsRight | 0 | 0 | Infinity | 0 | 0 | Infinity | 0 | 0 | | infinityTowardsLeft | 0 | 0 | -Infinity | 0 | -Infinity | 0 | 0 | 0 | | infinityAtRight | Infinity | 0 | 0 | 0 | Infinity | Infinity | 0 | 0 | | infinityAtLeft | -Infinity | 0 | 0 | 0 | -Infinity | -Infinity | 0 | 0 | | infinityLeftToRight | -Infinity | 0 | Infinity | 0 | NaN | NaN | 0 | 0 | | infinityRightToLeft | Infinity | 0 | -Infinity | 0 | NaN | NaN | 0 | 0 | | infinityTowardsBottom | 0 | 0 | 0 | Infinity | 0 | 0 | 0 | Infinity | | infinityTowardsTop | 0 | 0 | 0 | -Infinity | 0 | 0 | -Infinity | 0 | | infinityAtBottom | 0 | Infinity | 0 | 0 | 0 | 0 | Infinity | Infinity | | infinityAtTop | 0 | -Infinity | 0 | 0 | 0 | 0 | -Infinity | -Infinity | | infinityTopToBottom | 0 | -Infinity | 0 | Infinity | 0 | 0 | NaN | NaN | | infinityBottomToTop | 0 | Infinity | 0 | -Infinity | 0 | 0 | NaN | NaN | | bottomRightQuadrant | 0 | 0 | Infinity | Infinity | 0 | Infinity | 0 | Infinity | | bottomLeftQuadrant | 0 | 0 | -Infinity | Infinity | -Infinity | 0 | 0 | Infinity | | topRightQuadrant | 0 | 0 | Infinity | -Infinity | 0 | Infinity | -Infinity | 0 | | topLeftQuadrant | 0 | 0 | -Infinity | Infinity | -Infinity | 0 | 0 | Infinity | | planeTopBottomLeftRight | -Infinity | -Infinity | Infinity | Infinity | NaN | NaN | NaN | NaN | | planeTopBottomRightLeft | Infinity | -Infinity | -Infinity | Infinity | NaN | NaN | NaN | NaN | | planeBottomTopLeftRight | Infinity | -Infinity | Infinity | -Infinity | Infinity | Infinity | -Infinity | -Infinity | | planeBottomTopRightLeft | Infinity | Infinity | -Infinity | -Infinity | NaN | NaN | NaN | NaN |The consistent behavior is obviously a good sign, but I'd like to know if the spec is already explicit enough and browsers are strictly following it, or if they've just settled on identical behavior here by happenstance.
Also relevant are the definitions for top/left/right/bottom (bottom of 3. The DOMRect interfaces):
Note use of "the sum of".
x, y, width, height are all unrestricted doubles, which "is a floating point numeric type that corresponds to the set of all possible double-precision 64-bit IEEE 754 floating point numbers, finite, non-finite, and special "not a number" values (NaNs)".
I'm not acquainted with IEEE 754 to know if it specifically defines computations for minimum/maximum (which would include details for Infinity, e.g. "the minimum of any set of numbers, not including NaN, and including negative infinity, is negative infinity"), but given the previous concern over NaN propagation being addressed within this spec (rather than externally or implicitly), I'm wondering if Infinity should receive similar treatment.
I also don't know if "is NaN" is explicit enough as-is to imply "is the exact value NaN" (i.e. synonymous with JavaScript
Number.isNaN
) - I understand it not to imply "infinity is NaN", but this isn't explicit in the spec.