img.naturalWidth and naturalHeight return 0 for dimensionless SVG images
Categories
(Core :: Layout: Images, Video, and HTML Frames, defect)
Tracking
()
People
(Reporter: dholbert, Unassigned)
References
(Blocks 2 open bugs)
Details
(Keywords: webcompat:platform-bug)
Attachments
(4 files)
STR:
- Load attached testcase (which has an <img> pointing at a trivial dimensionless SVG data-URI document)
EXPECTED RESULTS:
The testcase should report img naturalWidth x naturalHeight: 300 x 150
ACTUAL RESULTS:
The testcase reports img naturalWidth x naturalHeight: 0 x 0
Chromium and WebKit give EXPECTED RESULTS.
Firefox gives ACTUAL RESULTS.
Note that we do report 300x150 for the img.width
and height
attributes, but we're returning 0
from naturalWidth
and naturalHeight
.
It looks like these attributes are all defined here in the HTML spec, in a non-normative section:
https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-width-dev
https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-naturalwidth-dev
In this case it seems Chrome/Safari are reporting the actual rendered width/height as the naturalWidth (because there is no actual "natural width" or "natural height" for this dimensionless image). I'm not yet finding spec justification for that, but there's at least one site that seems to rely on the Chrome/Safari behavior when computing an aspect ratio to kick off their sizing logic (which results in 0/0 = NaN in Firefox); see bug 1933708.
Reporter | ||
Updated•3 months ago
|
Reporter | ||
Comment 1•3 months ago
•
|
||
Using this more legacy-friendly testcase, I confirmed that this behavior goes back quite a long ways in Firefox; we show the same behavior[1] going back at least to NIghtly 2011-12-01 (Firefox 11 timeframe). So this has probably been the behavior ever since we implemented SVG-as-an-image, I'd guess.
[1] that same behavior being:
img width x height: 300 x 150
img naturalWidth x naturalHeight: 0 x 0
Reporter | ||
Comment 2•3 months ago
|
||
And Chromium's behavior goes back a long ways too; Chrome 37 (the oldest that BrowserStack lets me test on Win11) matches current Chrome in returning 300x150 for the naturalWidth x naturalHeight here.
Comment 3•3 months ago
|
||
See bug 1607081. I think this is just a duplicate of that.
Having said that the HTML spec says this...
https://html.spec.whatwg.org/multipage/embedded-content.html#embedded-content
image.naturalWidth
image.naturalHeightThese attributes return the natural dimensions of the image, or 0 if the dimensions are not known.
We don't know the dimensions do we? So we must return 0, no?
I've always thought (like Cameron did) that bug 1607081 is invalid per the HTML specification (as is this bug).
Comment 4•3 months ago
|
||
These attributes are not just defined by the (informative) note in the spec; below that, within the main text, we see:
The IDL attributes
naturalWidth
andnaturalHeight
must return the density-corrected natural width and height of the image, in CSS pixels, if the image has density-corrected natural width and height and is available, or else 0.
This seems pretty unambiguous. A dimensionless SVG has no natural width/height, and therefore these attributes must return 0.
So according to the HTML spec, I'd agree this is clearly invalid (and the other browsers have a bug).
However, maybe this is a case where we should accept that the webkit/blink behavior is more-or-less a de facto standard for the web, and the HTML spec (and our behavior) should be modified to reflect this?
Reporter | ||
Comment 5•3 months ago
|
||
Thanks for those references.
(In reply to Jonathan Kew [:jfkthame] from comment #4)
However, maybe this is a case where we should accept that the webkit/blink behavior is more-or-less a de facto standard for the web, and the HTML spec (and our behavior) should be modified to reflect this?
Hard to know, but I suspect this may be the case, given the longstanding Chromium/WebKit behavior here (and their collective dominance, paired with the fact that there is at least some web content that accidentally depends on their behavior).
I'll post some links to the WebKit code that seems to implement their current beahvior, for reference if/when we do end up updating the spec and/or our implementation to mitigate webcompat issues here.
Reporter | ||
Comment 6•3 months ago
•
|
||
Here is WebKit's HTMLImageElement::naturalWidth()
implementation.
With a bit of guesswork about the exact codepath, I think that function ends up calling this stack of functions to reach the relevant SVG-image sizing code:
CachedImage::unclampedImageSizeForRenderer
CachedImage::imageSizeForRenderer
SVGImageCache::imageSizeForRenderer
SVGImage::size
That size
function just returns SVGImage::m_intrinsicSize
which would have gotten its value in SVGImage::containerSize
And specifically this section seems to fall back to 300x150 when setting that value:https://searchfox.org/wubkat/rev/48c752dce43162935898b93cefa254a21a5e84c5/Source/WebCore/svg/graphics/SVGImage.cpp#148-149,172-180
IntSize SVGImage::containerSize() const
{
...
FloatSize currentSize;
if (rootElement->hasIntrinsicWidth() && rootElement->hasIntrinsicHeight())
currentSize = rootElement->currentViewportSizeExcludingZoom();
else
currentSize = rootElement->currentViewBoxRect().size();
// Use the default CSS intrinsic size if the above failed.
if (currentSize.isEmpty())
return IntSize(300, 150);
Reporter | ||
Comment 7•3 months ago
•
|
||
Note that the isEmpty
function at the end of my previous comment is defined here:
https://searchfox.org/wubkat/rev/48c752dce43162935898b93cefa254a21a5e84c5/Source/WebCore/platform/graphics/FloatSize.h#77
constexpr bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
So it seems like WebKit is explicitly declining to have an SVG image whose intrinsic height or width is zero, even if it's declared as such.
Reporter | ||
Comment 8•3 months ago
|
||
Chrome's behavior is a bit more subtle than WebKit's -- they do return a naturalWidth (or naturalHeight) of 0
if the image's svg
element is explicitly declared as having an 0px
width (or height).
It's only when the svg element is declared as having a percent-valued width
(or height
) that Chrome treats it as having a naturalWidth
(or naturalHeight
) that matches the fallback replaced-element size.
Reporter | ||
Comment 9•3 months ago
•
|
||
Here's a testcase to demonstrate that distinction, where Firefox/Chromium/WebKit all disagree on img naturalWidth x naturalHeight
. I've made the width
an explicit 0px
size here, vs. height an explicit 0%
size, and the length vs percentage are handled differently in Chromium:
- Firefox:
0 x 0
- Chromium:
0 x 150
- WebKit:
300 x 150
Reporter | ||
Comment 10•3 months ago
|
||
So I guess testcase 3 is showing that:
- WebKit refuses to accept that the natural width and height might actually be legitimately 0
- whereas Chrome accepts those as possible legitimate values, but still handles the "not-available/not-known" case by returning the appropriate component of the fallback 300x150 replaced-element dimensions.
- whereas Firefox accepts 0 as possible legitimate values and also handles the "not-available/not-known" case by returning 0 per spec.
Reporter | ||
Comment 11•3 months ago
|
||
Chrome's SVG-as-an-image implementation is in this file:
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/svg/graphics/svg_image.cc
...and intrinsic_size_
is the relevant member-variable for the purposes of this bug. They do indeed initialize it to 300x150 in some cases, here (kDefaultWidth
by kDefaultHeight
):
intrinsic_size_ = PhysicalSize::FromSizeFFloor(blink::ConcreteObjectSize(
sizing_info, gfx::SizeF(LayoutReplaced::kDefaultWidth,
LayoutReplaced::kDefaultHeight)));
They consider this to be a bug, per a comment here:
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/svg/graphics/svg_image.cc;l=706-707;drc=616d60fca655937c2b730db94fd32d37ddff3bb5
which points to this bug:
https://issues.chromium.org/issues/41357911
Reporter | ||
Comment 12•3 months ago
|
||
I dropped a comment on the Chromium bug report to see if their version of this can get retriaged.
Given that their version of the bug is much narrower than WebKit's version, and is known-to-be-a-bug, and we've got only one known compat issue associated, it seems conceivable that we can get alignment on the specced behavior that Firefox already implements here...
Reporter | ||
Comment 13•3 months ago
|
||
Here's a testcase checking a variety of width/height combinations, most of which should produce a naturalWidth or naturalHeight value of 0.
Firefox gives PASS: All subtests passed!
Chrome gives FAIL: found 24 failures. Check DevTools console for details
WebKit gives FAIL: found 60 failures. Check DevTools console for details
Reporter | ||
Comment 14•3 months ago
|
||
I filed https://bugs.webkit.org/show_bug.cgi?id=284341 on the WebKit behavior here.
Comment 15•3 months ago
|
||
So this does seem invalid (and a dupe of bug 1607081), but I'll leave it open for now; let's see if/how the other browsers respond to their bugs.
Reporter | ||
Comment 16•2 months ago
|
||
(In reply to Jonathan Kew [:jfkthame] from comment #15)
So this does seem invalid (and a dupe of bug 1607081), but I'll leave it open for now; let's see if/how the other browsers respond to their bugs.
Good news; there now seems to be a fair amount of ongoing progress on the Chromium bug which is a great sign.
I'll still leave this open since for now at least this is still a potential point of interop pain, but if Chromium's bug manages to get closed, I think we're good to close this out too.
Description
•