Bug 78902 - Integrate SVGUseElement within the new shadow root concept
Summary: Integrate SVGUseElement within the new shadow root concept
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: SVG (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nikolas Zimmermann
URL:
Keywords: InRadar
: 64419 64779 64781 (view as bug list)
Depends on:
Blocks: 78807 79568 79798
  Show dependency treegraph
 
Reported: 2012-02-17 08:10 PST by Nikolas Zimmermann
Modified: 2012-04-02 10:53 PDT (History)
16 users (show)

See Also:


Attachments
<use> without cloning prototype (205.97 KB, patch)
2012-02-17 08:13 PST, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Current prototype patch (42.28 KB, patch)
2012-02-17 08:16 PST, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch v1 (deleted)
2012-02-22 05:40 PST, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch v2 (deleted)
2012-02-22 06:47 PST, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch v3 (deleted)
2012-02-25 02:54 PST, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch v4 (deleted)
2012-02-28 03:40 PST, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Nikolas Zimmermann 2012-02-17 08:10:35 PST
Integrate SVGUseElement within the new shadow root concept.
Comment 1 Nikolas Zimmermann 2012-02-17 08:13:36 PST
Created attachment 127590 [details]
<use> without cloning prototype

Historical patch, some months ago: My attempt to rewrite <use> completly w/o any shadow trees.
The approach failed, as <text> selection etc. is not possible with that approach, as it renders <use> targets into ImageBuffers.
Maybe we can opt-it in for simple use-on-shape, situations, etc. as it's incredibe much faster than cloning.

NOTE: This is just for the record, so schenney can see it - it contains debug code, etc.
Comment 2 Nikolas Zimmermann 2012-02-17 08:16:10 PST
Created attachment 127591 [details]
Current prototype patch

And here's my new attempt: switches SVGUseElement to use ShadowRoot.
Die RenderSVGShadowTreeRootContainer & SVGShadowTreeElements!
Comment 3 Nikolas Zimmermann 2012-02-22 05:40:57 PST
Created attachment 128185 [details]
Patch v1
Comment 4 Nikolas Zimmermann 2012-02-22 05:42:28 PST
The code changes are actually below 50k, the rest is build system changes, file removal, and expectations updates - lots of them, due the changed shadow tree handling.

The patch should eliminate the root of all our past security bugs.
Comment 5 Nikolas Zimmermann 2012-02-22 05:59:27 PST
CC'ing more shadow dom folks. A pity, the bots don't like the patch (never seen that kind of crash)
Comment 6 Early Warning System Bot 2012-02-22 06:05:44 PST
Comment on attachment 128185 [details]
Patch v1

Attachment 128185 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/11562467
Comment 7 WebKit Review Bot 2012-02-22 06:11:43 PST
Comment on attachment 128185 [details]
Patch v1

Attachment 128185 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/11557492
Comment 8 Philippe Normand 2012-02-22 06:13:33 PST
Comment on attachment 128185 [details]
Patch v1

Attachment 128185 [details] did not pass gtk-ews (gtk):
Output: http://queues.webkit.org/results/11558488
Comment 9 Nikolas Zimmermann 2012-02-22 06:47:30 PST
Created attachment 128203 [details]
Patch v2
Comment 10 Dimitri Glazkov (Google) 2012-02-22 10:37:45 PST
Comment on attachment 128203 [details]
Patch v2

View in context: https://bugs.webkit.org/attachment.cgi?id=128203&action=review

Whoa, awesome patch (both in intent and in size :P)

The shadow DOM stuff looks good. Haven't looked at the SVG stuff closely, other than shadow tree management.

> Source/WebCore/css/SelectorChecker.cpp:-61
> -#if ENABLE(SVG)

(here and elsewhere) Why don't we need this flagged anymore?

> Source/WebCore/dom/Node.cpp:1523
> +bool Node::isInShadowTree() const

This could've probably be done as a separate patch.

> LayoutTests/platform/chromium/test_expectations.txt:-951
> -BUGCR23463 LEOPARD : svg/W3C-SVG-1.1/struct-symbol-01-b.svg = IMAGE
> -BUGCR23463 LINUX WIN : svg/W3C-SVG-1.1/struct-symbol-01-b.svg = IMAGE+TEXT
> -BUGCR23463 LINUX WIN : svg/W3C-SVG-1.1/struct-use-01-t.svg = PASS IMAGE+TEXT IMAGE

In these cases, we usually just comment them out, so that the previous bug info is preserved. Unless of course you fixed these!! :)
Comment 11 Nikolas Zimmermann 2012-02-22 10:46:01 PST
(In reply to comment #10)
> Whoa, awesome patch (both in intent and in size :P)
Thanks :-)

> The shadow DOM stuff looks good. Haven't looked at the SVG stuff closely, other than shadow tree management.
Excellent, I was looking for that kind of feedback. The SVG part can be reviewed by someone else, I think.
 
> > Source/WebCore/css/SelectorChecker.cpp:-61
> > -#if ENABLE(SVG)
> 
> (here and elsewhere) Why don't we need this flagged anymore?
isSVGElement() is always available now, and XLinkNames isn't surrounded by ENABLE(SVG) guards, so we can safely remove this.

> 
> > Source/WebCore/dom/Node.cpp:1523
> > +bool Node::isInShadowTree() const
> 
> This could've probably be done as a separate patch.
Sure, but it's just this single line?

> 
> > LayoutTests/platform/chromium/test_expectations.txt:-951
> > -BUGCR23463 LEOPARD : svg/W3C-SVG-1.1/struct-symbol-01-b.svg = IMAGE
> > -BUGCR23463 LINUX WIN : svg/W3C-SVG-1.1/struct-symbol-01-b.svg = IMAGE+TEXT
> > -BUGCR23463 LINUX WIN : svg/W3C-SVG-1.1/struct-use-01-t.svg = PASS IMAGE+TEXT IMAGE
> 
> In these cases, we usually just comment them out, so that the previous bug info is preserved. Unless of course you fixed these!! :)
I hope its fixed now, but I can of course only comment them, will include these changes in a follow-up patch, if needed.
Comment 12 Stephen Chenney 2012-02-22 14:13:53 PST
Comment on attachment 128203 [details]
Patch v2

View in context: https://bugs.webkit.org/attachment.cgi?id=128203&action=review

I'm not sure this will address all the security issues we've had, but that is no reason to hold back. I will probably apply it locally and see what difference it makes to the pathological cases we have. I may also need to fix https://bugs.webkit.org/show_bug.cgi?id=77764, sooner rather than later.

> Source/WebCore/css/SelectorChecker.cpp:-449
> -    // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree

Are you sure that whatever mechanism controls Style and shadow nodes will correctly work for SVG semantics?

> Source/WebCore/dom/EventDispatcher.cpp:70
> +    if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(referenceNode))

Won't this fail to build with SVG disabled, due to the lack of SVGElementInstance?

>> Source/WebCore/dom/Node.cpp:1523
>> +bool Node::isInShadowTree() const
> 
> This could've probably be done as a separate patch.

There are a couple of other portion of this patch that add const in existing code. I think they all go in one separate patch.

> Source/WebCore/dom/ScriptElement.cpp:202
>      if (!isScriptForEventSupported())

Is there code elsewhere to prevent script execution inside the shadow tree? https://bugs.webkit.org/show_bug.cgi?id=64419

> Source/WebCore/rendering/svg/RenderSVGModelObject.cpp:165
> +    return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag);

Maybe a method to encapsulate node()->hasTagName(SVGNames::useTag)? It seems to appear a lot.

> LayoutTests/platform/chromium/test_expectations.txt:-945
> -BUGCR8763 MAC : svg/custom/use-on-g-containing-foreignObject-and-image.svg = IMAGE

Reiterating Dimitri's request. Please comment out rather than removing.

Please also create a bug, assigned to me, to update the expectations when this change goes in and the build bots have produced new results. Mark the new bug as depending on this bug.

> LayoutTests/platform/chromium/test_expectations.txt:4374
> +

You can also mark all these as "... = TEXT IMAGE TEXT+IMAGE PASS" if you want to cover all bases. I generally do this to avoid noise for unexpected passing tests.
Comment 13 Nikolas Zimmermann 2012-02-23 07:48:58 PST
(In reply to comment #12)
> I'm not sure this will address all the security issues we've had, but that is no reason to hold back. I will probably apply it locally and see what difference it makes to the pathological cases we have. I may also need to fix https://bugs.webkit.org/show_bug.cgi?id=77764, sooner rather than later.
It won't address all, but lots of them (instanceUpdates-blocked concept is gone, which was needed as we had races before in that code). Did you have luck with the corner cases?

> > Source/WebCore/css/SelectorChecker.cpp:-449
> > -    // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
> 
> Are you sure that whatever mechanism controls Style and shadow nodes will correctly work for SVG semantics?
Yeah, the SVG shadow tree is now styled correctly, w/o the need for us to early exit in checkSelector, and rely on a custom setStyle call afterwards, that correctly resolves the shadow tree styles with the <use> element as parent. It's all handled transparently by ShadowRoot now.

> > Source/WebCore/dom/EventDispatcher.cpp:70
> > +    if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(referenceNode))
> 
> Won't this fail to build with SVG disabled, due to the lack of SVGElementInstance?
This is guarded by ENABLE(SVG) already?

> >> Source/WebCore/dom/Node.cpp:1523
> > This could've probably be done as a separate patch.
> 
> There are a couple of other portion of this patch that add const in existing code. I think they all go in one separate patch.
Okay, I'll look for the other cases, and split them off.
 
> > Source/WebCore/dom/ScriptElement.cpp:202
> >      if (!isScriptForEventSupported())
> 
> Is there code elsewhere to prevent script execution inside the shadow tree? https://bugs.webkit.org/show_bug.cgi?id=64419
Thanks for the hint, I found the related bug 64781: that's exactly what I've fixed here. (shadow tree creation time)

> > Source/WebCore/rendering/svg/RenderSVGModelObject.cpp:165
> > +    return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag);
> 
> Maybe a method to encapsulate node()->hasTagName(SVGNames::useTag)? It seems to appear a lot.
I could add a new method, but that needs to be virtual, and on SVGElement - as we certainly don't want to pollute Node.h for this. That would look like static_cast<SVGElement*>(node())->isSVGUseElement() - is it better? Certainly not faster.
 
> > LayoutTests/platform/chromium/test_expectations.txt:-945
> > -BUGCR8763 MAC : svg/custom/use-on-g-containing-foreignObject-and-image.svg = IMAGE
> 
> Reiterating Dimitri's request. Please comment out rather than removing.
Will take care.
 
> Please also create a bug, assigned to me, to update the expectations when this change goes in and the build bots have produced new results. Mark the new bug as depending on this bug.
Ok, will do.

> > LayoutTests/platform/chromium/test_expectations.txt:4374
> You can also mark all these as "... = TEXT IMAGE TEXT+IMAGE PASS" if you want to cover all bases. I generally do this to avoid noise for unexpected passing tests.
Ok.
Comment 14 Stephen Chenney 2012-02-23 08:13:30 PST
(In reply to comment #13)
> (In reply to comment #12)
> > I'm not sure this will address all the security issues we've had, but that is no reason to hold back. I will probably apply it locally and see what difference it makes to the pathological cases we have. I may also need to fix https://bugs.webkit.org/show_bug.cgi?id=77764, sooner rather than later.
> It won't address all, but lots of them (instanceUpdates-blocked concept is gone, which was needed as we had races before in that code). Did you have luck with the corner cases?

Today I will get to testing all the odd crash cases we have - I hope.

> > > Source/WebCore/dom/EventDispatcher.cpp:70
> > > +    if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(referenceNode))
> > 
> > Won't this fail to build with SVG disabled, due to the lack of SVGElementInstance?
> This is guarded by ENABLE(SVG) already?

Sorry, needed more context. This is in the #else of a #if ENABLED(SVG) block, so it is not protected. The code is protected at Debug runtime with an ASSERT_NEVER_REACHED, but that line will still try to compile in.

> 
> > > Source/WebCore/rendering/svg/RenderSVGModelObject.cpp:165
> > > +    return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag);
> > 
> > Maybe a method to encapsulate node()->hasTagName(SVGNames::useTag)? It seems to appear a lot.
> I could add a new method, but that needs to be virtual, and on SVGElement - as we certainly don't want to pollute Node.h for this. That would look like static_cast<SVGElement*>(node())->isSVGUseElement() - is it better? Certainly not faster.

Sounds fine. I agree that it should be left as is.

Thanks for the expectations changes.
Comment 15 Nikolas Zimmermann 2012-02-23 08:33:01 PST
(In reply to comment #14)
> > > Won't this fail to build with SVG disabled, due to the lack of SVGElementInstance?
> > This is guarded by ENABLE(SVG) already?
> 
> Sorry, needed more context. This is in the #else of a #if ENABLED(SVG) block, so it is not protected. The code is protected at Debug runtime with an ASSERT_NEVER_REACHED, but that line will still try to compile in.
Heh, look again, the #else branch is removed as well. This won't affect non-SVG builds, they still work fine.
Comment 16 Nikolas Zimmermann 2012-02-23 08:37:25 PST
(In reply to comment #12)
> > This could've probably be done as a separate patch.
> 
> There are a couple of other portion of this patch that add const in existing code. I think they all go in one separate patch.
I looked again, the only const change in isInShadowTree - do you think that's worth to split off?? I'd say no, if it's just this single change.
Comment 17 Stephen Chenney 2012-02-23 08:46:08 PST
(In reply to comment #15)
> (In reply to comment #14)
> > > > Won't this fail to build with SVG disabled, due to the lack of SVGElementInstance?
> > > This is guarded by ENABLE(SVG) already?
> > 
> > Sorry, needed more context. This is in the #else of a #if ENABLED(SVG) block, so it is not protected. The code is protected at Debug runtime with an ASSERT_NEVER_REACHED, but that line will still try to compile in.
> Heh, look again, the #else branch is removed as well. This won't affect non-SVG builds, they still work fine.

O how I wish for a side-by-side review system.

And I too could only find one const. Given you are also changing a comment, and that comment is specific to this change (as is the const-ness?) I would leave it in this patch.
Comment 18 Nikolas Zimmermann 2012-02-25 02:45:43 PST
*** Bug 64419 has been marked as a duplicate of this bug. ***
Comment 19 Nikolas Zimmermann 2012-02-25 02:46:18 PST
*** Bug 64779 has been marked as a duplicate of this bug. ***
Comment 20 Nikolas Zimmermann 2012-02-25 02:46:44 PST
*** Bug 64781 has been marked as a duplicate of this bug. ***
Comment 21 Nikolas Zimmermann 2012-02-25 02:54:09 PST
Created attachment 128862 [details]
Patch v3

Updated patch against trunk, and fixed chromium expectations.
Comment 22 Zoltan Herczeg 2012-02-28 01:48:14 PST
Comment on attachment 128862 [details]
Patch v3

Wow, really nice patch. I am always happy if we can simplify the code, and we can remove a lot of lines.

I trust you that the expected updates are correct.

Some thoughts:

View in context: https://bugs.webkit.org/attachment.cgi?id=128862&action=review

> Source/WebCore/ChangeLog:128
> +            <defs><rect id="rect">>/defs> <use xlink:href="#rect"/>. Now from a script we change the rect x/y/width/height attributes:

<defs><rect id="rect">>/defs>
The > should be <

> Source/WebCore/dom/EventDispatcher.cpp:64
> +    ASSERT(referenceNode);
> +    if (!referenceNode->isSVGElement() || !referenceNode->isInShadowTree())
> +        return referenceNode;
> +
>  #if ENABLE(SVG)

I think the lines above should be covered by the #if directive even if it can be compiled without SVG.

> Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp:64
> +    FloatSize translation;
> +    if (useElement) {
> +        SVGLengthContext lengthContext(useElement);
> +        translation = FloatSize(useElement->x().value(lengthContext), useElement->y().value(lengthContext));
> +        if (translation != m_lastTranslation)
> +            m_needsTransformUpdate = true;
> +        m_lastTranslation = translation;
> +    }

FloatSize translation probably can be moved inside the if:
FloatSize translation(FloatSize(useElement->x().value(lengthContext), useElement->y().value(lengthContext)));

> Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp:71
> +    SVGElement* correspondingElement = svg->correspondingElement();
> +    if (svg->isInShadowTree() && correspondingElement) {

I think the two conditions around the && could be swapped. Little perf gain.

> Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp:113
> +        SVGLengthContext lengthContext(element);
> +        if (useElement->hasAttribute(SVGNames::widthAttr))
> +            m_viewport.setWidth(useElement->width().value(lengthContext));
> +        else if (isSymbolElement && svg->hasAttribute(SVGNames::widthAttr)) {
> +            SVGLength containerWidth(LengthModeWidth, "100%");
> +            m_viewport.setWidth(containerWidth.value(lengthContext));
> +        }
> +
> +        if (useElement->hasAttribute(SVGNames::heightAttr))
> +            m_viewport.setHeight(useElement->height().value(lengthContext));
> +        else if (isSymbolElement && svg->hasAttribute(SVGNames::heightAttr)) {
> +            SVGLength containerHeight(LengthModeHeight, "100%");
> +            m_viewport.setHeight(containerHeight.value(lengthContext));
> +        }

Just some thinking: setting up lengthContext if both "ifs" are false is unnecessary. Is it cheap enough? If not, perhaps we should avoid that, especially if the "ifs" are likely false.

> Source/WebCore/svg/SVGElement.cpp:484
> +        style = parent->renderer() ? parent->renderer()->style() : 0;

For me personally this looks ugly. Can't we just use a second if? And put a renderer into a local vvariable?

> Source/WebCore/svg/SVGLocatable.cpp:48
> -    for (ContainerNode* n = element->parentNode(); n; n = n->parentNode()) {
> -        if (isViewportElement(n))
> -            return static_cast<SVGElement*>(n);
> +    for (Element* current = element->parentOrHostElement(); current; current = current->parentOrHostElement()) {
> +        if (isViewportElement(current))
> +            return static_cast<SVGElement*>(current);

I know it was not in the old code, but perhaps we could add an ASSERT here. Or is it unnecessary?

> Source/WebCore/svg/SVGLocatable.cpp:60
> -    for (ContainerNode* n = element->parentNode(); n; n = n->parentNode()) {
> -        if (isViewportElement(n))
> -            farthest = static_cast<SVGElement*>(n);
> +    for (Element* current = element->parentOrHostElement(); current; current = current->parentOrHostElement()) {
> +        if (isViewportElement(current))
> +            farthest = static_cast<SVGElement*>(current);

ditto

> Source/WebCore/svg/SVGLocatable.cpp:88
> +    SVGElement* currentElement = element;
> +    while (currentElement) {

can currentElement be NULL? If not, we could make this a do ... while()

> Source/WebCore/svg/SVGUseElement.cpp:99
> +    RefPtr<SVGUseElement> use = adoptRef(new SVGUseElement(tagName, document));
> +    use->ensureShadowRoot();
> +    return use.release();

Can't this ensureShadowRoot() go to the constructor?
Comment 23 Nikolas Zimmermann 2012-02-28 03:04:38 PST
(In reply to comment #22)
> (From update of attachment 128862 [details])
> Wow, really nice patch. I am always happy if we can simplify the code, and we can remove a lot of lines.
Thanks.

> The > should be <
Fixed.

> I think the lines above should be covered by the #if directive even if it can be compiled without SVG.
Fixed.

> FloatSize translation probably can be moved inside the if:
> FloatSize translation(FloatSize(useElement->x().value(lengthContext), useElement->y().value(lengthContext)));
Fixed.

> I think the two conditions around the && could be swapped. Little perf gain.
Fixed.

> Just some thinking: setting up lengthContext if both "ifs" are false is unnecessary. Is it cheap enough? If not, perhaps we should avoid that, especially if the "ifs" are likely false.
Yes, we could avoid that, but I guess it's not worth it, lengthContext construction is cheap.

> For me personally this looks ugly. Can't we just use a second if? And put a renderer into a local vvariable?
Fixed.
 
> I know it was not in the old code, but perhaps we could add an ASSERT here. Or is it unnecessary?
No, it doesn't need to be a viewport element as parent.


> can currentElement be NULL? If not, we could make this a do ... while()
The whole construct makes no sense, I'll make it use a for-loop instead, operating on Elements, no need to make this SVGElement only, this is ancient legacy code.

> Can't this ensureShadowRoot() go to the constructor?
I followed the existing style in the other shadow tree constructing elements. I guess it can call virtual functions, and thus can't run from the constructor.
Comment 24 Nikolas Zimmermann 2012-02-28 03:40:37 PST
Created attachment 129223 [details]
Patch v4
Comment 25 Zoltan Herczeg 2012-02-28 03:53:24 PST
Comment on attachment 129223 [details]
Patch v4

r=me nincs work.
Comment 26 Nikolas Zimmermann 2012-02-28 04:13:54 PST
Committed r109097: <http://trac.webkit.org/changeset/109097>
Comment 27 Nikolas Zimmermann 2012-02-28 05:15:44 PST
Ossy rebaselined Qt in r109099. I rebaselined Gtk in r109100.
Win bots are still so broken, that I'm unable to obtain new results for Win, it early exits after 500 failures, before svg/ is reached :(

Still waiting for the SL bots to cycle.
Comment 28 Nikolas Zimmermann 2012-02-28 07:26:12 PST
Stephen, can you have a look at the chromium expectations, and the other <use> security bugs?
Comment 29 Stephen Chenney 2012-02-28 07:45:19 PST
(In reply to comment #28)
> Stephen, can you have a look at the chromium expectations, and the other <use> security bugs?

Yep. And I will shortly have up a patch for excluding invalid elements from <use>. That alone fixes the security issues even before your change.
Comment 30 Nikolas Zimmermann 2012-03-01 05:41:54 PST
I can't access bug 79798. I hope Stephen can take care of 79568, so we can close this bug soon.
Comment 31 David Kilzer (:ddkilzer) 2012-03-04 10:18:52 PST
<rdar://problem/10980087>
Comment 32 Stephen Chenney 2012-03-07 08:35:16 PST
You can close this if you would like. https://bugs.webkit.org/show_bug.cgi?id=79568 is tracking the chromium expectations and there is nothing in them that suggest problems with this patch.
Comment 33 Eric Seidel (no email) 2012-03-27 12:48:53 PDT
Comment on attachment 129223 [details]
Patch v4

Cleared Zoltan Herczeg's review+ from obsolete attachment 129223 [details] so that this bug does not appear in http://webkit.org/pending-commit.