Skip to content

Commit aa1b9b2

Browse files
Ahmad-S792Ahmad Saleem
authored andcommitted
SVGLength percentage resolution fails for elements inside non-instanced <symbol> or when viewportElement() returns nullptr
https://bugs.webkit.org/show_bug.cgi?id=303127 rdar://165431008 Reviewed by Simon Fraser. SVGLength.value was throwing `NotSupportedError` when resolving percentage values for elements inside non-instanced <symbol> elements or display:none containers. According to the SVG specification [1], either an <svg> element or a <symbol> element that is instanced by a <use> element establishes a new viewport. For non-instanced <symbol> elements, the nearest ancestor <svg> should provide the viewport for percentage resolution. Fix viewport calculation by extending viewportElement() with a ViewportElementType enum that allows callers to specify whether they want any viewport element (including <symbol>) or specifically an <svg> element. This eliminates the need for manual ancestor walks in computeViewportSize() while preserving the original behavior for normal viewport elements. When ViewportElementType::SVGSVGOnly is specified, viewportElement() now walks up the ancestor tree to find the nearest <svg> element, skipping <symbol> elements. This matches other browser engines (Blink / Chromium and Gecko / Firefox). [1] https://svgwg.org/svg2-draft/coords.html#EstablishingANewSVGViewport NOTE: We still don't progress WPT due to floating point issue with height in WPT test but it progress for width. * Source/WebCore/svg/SVGElement.cpp: (WebCore::SVGElement::viewportElement const): * Source/WebCore/svg/SVGElement.h: * Source/WebCore/svg/SVGLengthContext.cpp: (WebCore::SVGLengthContext::computeViewportSize const): * LayoutTests/imported/w3c/web-platform-tests/svg/geometry/svg-baseval-in-display-none-expected.txt: Partial Progression Canonical link: https://commits.webkit.org/304197@main
1 parent bd18128 commit aa1b9b2

File tree

4 files changed

+20
-8
lines changed

4 files changed

+20
-8
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11

22
PASS With em
3-
FAIL With em and percentage The operation is not supported.
3+
FAIL With em and percentage assert_equals: r1.height expected 120 but got 120.00000762939453
44

Source/WebCore/svg/SVGElement.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,17 @@ SVGSVGElement* SVGElement::ownerSVGElement() const
230230
return nullptr;
231231
}
232232

233-
SVGElement* SVGElement::viewportElement() const
233+
SVGElement* SVGElement::viewportElement(ViewportElementType type) const
234234
{
235235
// This function needs shadow tree support - as RenderSVGContainer uses this function
236-
// to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
236+
// to determine the "overflow" property. <use> on <symbol> wouldn't work otherwise.
237237
auto* node = parentNode();
238238
while (node) {
239-
if (is<SVGSVGElement>(*node) || is<SVGImageElement>(*node) || node->hasTagName(SVGNames::symbolTag))
240-
return downcast<SVGElement>(node);
239+
if (is<SVGSVGElement>(*node) || is<SVGImageElement>(*node))
240+
return dynamicDowncast<SVGElement>(node);
241+
242+
if (type == ViewportElementType::Any && node->hasTagName(SVGNames::symbolTag))
243+
return dynamicDowncast<SVGElement>(node);
241244

242245
node = node->parentOrShadowHostNode();
243246
}

Source/WebCore/svg/SVGElement.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,13 @@ class SVGElement : public StyledElement, public SVGPropertyOwner {
7070
bool isOutermostSVGSVGElement() const;
7171

7272
SVGSVGElement* ownerSVGElement() const;
73-
SVGElement* viewportElement() const;
73+
74+
enum class ViewportElementType : uint8_t {
75+
Any, // Returns first SVGSVGElement, SVGImageElement, or symbol
76+
SVGSVGOnly // Returns only SVGSVGElement
77+
};
78+
79+
SVGElement* viewportElement(ViewportElementType = ViewportElementType::Any) const;
7480

7581
String title() const override;
7682
virtual bool supportsMarkers() const { return false; }

Source/WebCore/svg/SVGLengthContext.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "LocalFrame.h"
3434
#include "RenderStyleInlines.h"
3535
#include "RenderView.h"
36+
#include "SVGElement.h"
3637
#include "SVGElementTypeHelpers.h"
3738
#include "SVGSVGElement.h"
3839
#include "StyleLengthResolution.h"
@@ -421,6 +422,8 @@ std::optional<FloatSize> SVGLengthContext::viewportSize() const
421422

422423
std::optional<FloatSize> SVGLengthContext::computeViewportSize() const
423424
{
425+
using ViewportElementType = SVGElement::ViewportElementType;
426+
424427
ASSERT(m_context);
425428

426429
// Root <svg> element lengths are resolved against the top level viewport,
@@ -432,8 +435,8 @@ std::optional<FloatSize> SVGLengthContext::computeViewportSize() const
432435
if (m_context->isOutermostSVGSVGElement())
433436
return downcast<SVGSVGElement>(*protectedContext()).currentViewportSizeExcludingZoom();
434437

435-
// Take size from nearest viewport element.
436-
RefPtr svg = dynamicDowncast<SVGSVGElement>(m_context->viewportElement());
438+
// Take size from nearest SVGSVGElement, skipping over <symbol> elements.
439+
RefPtr svg = dynamicDowncast<SVGSVGElement>(m_context->viewportElement(ViewportElementType::SVGSVGOnly));
437440
if (!svg)
438441
return std::nullopt;
439442

0 commit comments

Comments
 (0)