Bug 94469 - enable <animate> of viewBox attribute in <view> element
Summary: enable <animate> of viewBox attribute in <view> element
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: SVG (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nikolas Zimmermann
URL: https://bugzilla.mozilla.org/attachme...
Keywords: InRadar
: 196554 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-08-20 05:21 PDT by bugmenot
Modified: 2019-09-13 11:22 PDT (History)
15 users (show)

See Also:


Attachments
Patch (12.59 KB, patch)
2019-09-03 04:21 PDT, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch (29.04 KB, patch)
2019-09-05 03:20 PDT, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch (18.01 KB, patch)
2019-09-10 14:16 PDT, Nikolas Zimmermann
no flags Details | Formatted Diff | Diff
Patch (17.85 KB, patch)
2019-09-13 04:21 PDT, 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 bugmenot 2012-08-20 05:21:19 PDT
testcase in URL field: zoom out on click when at #w

Testing revealed <animate> either as a child element of <view> like in the testcase, or outside it with xlink:href="#w" (at http://imgh.us/twZoomOutTest.svg#w ) fails to zoom the viewBox out to show the whole SVG.
The begin="click" is only in the testcase for easier manual testing.
Testcase works in Opera, not in Firefox.
Comment 1 bugmenot 2012-09-10 05:54:16 PDT
Mozilla has just fixed this in Firefox nightly builds:
https://bugzilla.mozilla.org/show_bug.cgi?id=783995
Comment 2 Nikolas Zimmermann 2019-09-03 03:43:08 PDT
I have a patch for this, will upload it soon.
Comment 3 Nikolas Zimmermann 2019-09-03 04:21:37 PDT
Created attachment 377887 [details]
Patch
Comment 4 Nikolas Zimmermann 2019-09-03 04:23:16 PDT
My first patch after 7 years :-) Feels like home.
NOTE: I plan to add more test coverage, especially dynamic updates for all the properties that we care about in SVGViewElement, just wanted to test the whole toolchain: webkit-patch, prepare-ChangeLog in combination with Git. Works like a charme!
Comment 5 Sam Weinig 2019-09-03 07:11:13 PDT
(In reply to Nikolas Zimmermann from comment #4)
> My first patch after 7 years :-) Feels like home.
> NOTE: I plan to add more test coverage, especially dynamic updates for all
> the properties that we care about in SVGViewElement, just wanted to test the
> whole toolchain: webkit-patch, prepare-ChangeLog in combination with Git.
> Works like a charme!

!!
Comment 6 Said Abou-Hallawa 2019-09-03 10:48:01 PDT
Comment on attachment 377887 [details]
Patch

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

Welcome back Niko.

> Source/WebCore/ChangeLog:10
> +        visual effect. If a SVGSVGElement references a SVGViewElement, e.g. by loading an URL like
> +        "test.svg#customView", the custom view if parsed once in SVGSVGElement::scrollToFragment().

This statement is a little bit hard to read.

> Source/WebCore/svg/SVGSVGElement.cpp:669
> +            if (rootElement->m_currentViewElement)

Should we check if (rootElement->m_currentViewElement != viewElement) before connecting the rootElement to the same viewElement?

> Source/WebCore/svg/SVGSVGElement.cpp:670
> +                rootElement->m_currentViewElement->resetTargetElement();

Should we ASSERT(rootElement->m_currentViewElement->targetElement() == rootElement);?

> Source/WebCore/svg/SVGSVGElement.h:164
> +    WeakPtr<SVGViewElement> m_currentViewElement { nullptr };

Is there a SVGViewElement per SVGSVGElement? What happens if an HTML page references the same SVG but with different views, e.g. "test.svg#customView1", "test.svg#customView2"? We may not optimize this case now and treat these URLs as different URLs. But this may change in the future.

> LayoutTests/ChangeLog:8
> +        Add a new reftest demonstrating that animations of SVG <view> elements now behave as expected.

Should we include a test case for referencing the same SVG from the same HTML but with different view elements?

> LayoutTests/svg/custom/animation-on-view-element-expected.html:15
> +  <iframe style="border: none" onload="loaded()" width='200' height='200' src='resources/animation-on-view-element-final.svg'></iframe>

Why do we have to have two SVGs: one for the test page and one for the expected page? Can't we use one SVG with two different views: one covers the whole SVG and the other one animates till it cover the whole SVG?

> LayoutTests/svg/custom/animation-on-view-element.html:17
> +  <iframe id="svgFrame" style="border: none" onload="loaded()" width='200' height='200' src='resources/animation-on-view-element.svg#customView'></iframe>

Should not <img src='resources/animation-on-view-element.svg#customView'> work the same way?

> LayoutTests/svg/custom/resources/animation-on-view-element.svg:1
> +<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" id="outermostSVG">

What is the use of id="outermostSVG"?

> LayoutTests/svg/custom/resources/animation-on-view-element.svg:14
> +    <animate attributeName="viewBox" dur="2s" begin="1s" to="0 0 200 200" fill="freeze"/>

Another way to do this or maybe it can be used in another test is 

    <set attributeName="viewBox" to="0 0 200 200"/>
Comment 7 Said Abou-Hallawa 2019-09-03 12:43:44 PDT
Should https://bugs.webkit.org/show_bug.cgi?id=196554 be duped to this one?
Comment 8 Nikolas Zimmermann 2019-09-03 13:30:35 PDT
(In reply to Said Abou-Hallawa from comment #6)
> Welcome back Niko.
Thanks Said!

> 
> > Source/WebCore/ChangeLog:10
> > +        visual effect. If a SVGSVGElement references a SVGViewElement, e.g. by loading an URL like
> > +        "test.svg#customView", the custom view if parsed once in SVGSVGElement::scrollToFragment().
> 
> This statement is a little bit hard to read.
Indeed, and wrong as well, I will revisit this.

> 
> > Source/WebCore/svg/SVGSVGElement.cpp:669
> > +            if (rootElement->m_currentViewElement)
> 
> Should we check if (rootElement->m_currentViewElement != viewElement) before
> connecting the rootElement to the same viewElement?
To my current understanding, this should not be possible, as the scrollToFragment() path should only be executed once per page load.

I am currently preparing a few more tests to clarify all the corner cases and document the intended behavior. Let us rediscuss this, once I am confident, if it is possible to trigger this condition or not.

> 
> > Source/WebCore/svg/SVGSVGElement.cpp:670
> > +                rootElement->m_currentViewElement->resetTargetElement();
> 
> Should we ASSERT(rootElement->m_currentViewElement->targetElement() ==
> rootElement);?
Good idea.

 
> > Source/WebCore/svg/SVGSVGElement.h:164
> > +    WeakPtr<SVGViewElement> m_currentViewElement { nullptr };
> 
> Is there a SVGViewElement per SVGSVGElement?
The outermost SVG element of a document, could reference max. one SVGViewElement.

> What happens if an HTML page
> references the same SVG but with different views, e.g.
> "test.svg#customView1", "test.svg#customView2"?
These are separated documents, I see no issue?

> We may not optimize this
> case now and treat these URLs as different URLs. But this may change in the
> future.
I see - you are worried that the same <view> element is referenced by multiple "outermost SVG elements", steming from different documents.

This would affect a lot more places throughout the SVG codebase.

> 
> > LayoutTests/ChangeLog:8
> > +        Add a new reftest demonstrating that animations of SVG <view> elements now behave as expected.
> 
> Should we include a test case for referencing the same SVG from the same
> HTML but with different view elements?
Sure, I plan to add exactly a test like this. Also we should check the SVGViewSpec is correct, also in cases when the view element is animated.

> 
> > LayoutTests/svg/custom/animation-on-view-element-expected.html:15
> > +  <iframe style="border: none" onload="loaded()" width='200' height='200' src='resources/animation-on-view-element-final.svg'></iframe>
> 
> Why do we have to have two SVGs: one for the test page and one for the
> expected page? Can't we use one SVG with two different views: one covers the
> whole SVG and the other one animates till it cover the whole SVG?
Ahh, just stupidity :-) I uploaded the patch early, and did not carefully check the test yet - you are right, I will fix this.

> 
> > LayoutTests/svg/custom/animation-on-view-element.html:17
> > +  <iframe id="svgFrame" style="border: none" onload="loaded()" width='200' height='200' src='resources/animation-on-view-element.svg#customView'></iframe>
> 
> Should not <img src='resources/animation-on-view-element.svg#customView'>
> work the same way?
From the visual point of view yes, but I have no access to the content document in that case, this only works using <embed> / <object> / <iframe>.
In this particular test, I am modifying the SVG currentTime attribute and thus need access to the content document from the host document.

> 
> > LayoutTests/svg/custom/resources/animation-on-view-element.svg:1
> > +<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" id="outermostSVG">
> 
> What is the use of id="outermostSVG"?
This is a relict from the original test case which used begin="outermostSVG.click" (just with a different naming convention for the id).

> 
> > LayoutTests/svg/custom/resources/animation-on-view-element.svg:14
> > +    <animate attributeName="viewBox" dur="2s" begin="1s" to="0 0 200 200" fill="freeze"/>
> 
> Another way to do this or maybe it can be used in another test is 
> 
>     <set attributeName="viewBox" to="0 0 200 200"/>
Sure, we should check this as well. I tried to stay as close as possible to the original test case referenced in this bug report.

Thanks Said for the review! More tests and checks will follow.
Comment 9 Nikolas Zimmermann 2019-09-03 13:39:17 PDT
*** Bug 196554 has been marked as a duplicate of this bug. ***
Comment 10 Nikolas Zimmermann 2019-09-03 13:39:33 PDT
(In reply to Said Abou-Hallawa from comment #7)
> Should https://bugs.webkit.org/show_bug.cgi?id=196554 be duped to this one?

Done.
Comment 11 Daniel Bates 2019-09-04 16:47:53 PDT
Welcome back!!!
Comment 12 Nikolas Zimmermann 2019-09-05 03:20:55 PDT
Created attachment 378072 [details]
Patch
Comment 13 Nikolas Zimmermann 2019-09-05 03:21:46 PDT
(In reply to Daniel Bates from comment #11)
> Welcome back!!!

Thanks, nice to hear from you again Daniel :-)
Comment 14 Nikolas Zimmermann 2019-09-05 03:22:53 PDT
Said, please check again. I've added more assertions, incorporated your comments and added two more layout tests.
Comment 15 Daniel Bates 2019-09-05 03:42:13 PDT
Comment on attachment 378072 [details]
Patch

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

> Source/WebCore/svg/SVGSVGElement.cpp:670
> +                ASSERT(rootElement->m_currentViewElement->targetElement());

Can this assert be removed given the one below?
Comment 16 Nikolas Zimmermann 2019-09-05 04:34:47 PDT
(In reply to Daniel Bates from comment #15)
> Comment on attachment 378072 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=378072&action=review
> 
> > Source/WebCore/svg/SVGSVGElement.cpp:670
> > +                ASSERT(rootElement->m_currentViewElement->targetElement());
> 
> Can this assert be removed given the one below?

In principle yes, I split them up to to differentiate between the "targetElement is null" and "the targetElement differs from the rootElement" (rootElement is already non-null).
Comment 17 Said Abou-Hallawa 2019-09-05 11:05:53 PDT
Comment on attachment 378072 [details]
Patch

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

> Source/WebCore/ChangeLog:12
> +        The settings from the SVGViewElement are only pasrsed onco in SVGSVGElement::scrollToFragment(). Dynamic updates

onco -> once

> Source/WebCore/ChangeLog:14
> +        the SVGSVGElement does not re-evaluates its viewBox. Fix that by introducing a link between SVGSVGElement

does not re-evaluates -> does not re-evaluate

> LayoutTests/ChangeLog:22
> +        Verify that dynamic updates to the <view> element in the external SVG, are reflect in the SVGViewSpec API as well (SVGSVGElement::currentView).

This test is great but I think it deserves a separate patch because most of it is not related to this patch and can pass without it.

> LayoutTests/svg/dom/SVGViewSpec-multiple-views.html:124
> +    iframeElement.contentDocument.documentElement.getElementById("view2").setAttribute("viewBox", "10 10 30 30");
> +
> +    debug("");
> +    debug("Check viewBox value after modification");
> +    shouldBe("currentView.viewBox.baseVal.x", "10");
> +    shouldBe("currentView.viewBox.baseVal.y", "10");
> +    shouldBe("currentView.viewBox.baseVal.width", "30");
> +    shouldBe("currentView.viewBox.baseVal.height", "30");
> +    shouldBeEqualToString("currentView.viewBoxString", "10 10 30 30");

This section is the only one that calls setAttribute("viewBox"). So I think the rest of this test can pass without this patch. I guess this is because of the missing SVGViewElement::svgAttributeChanged().

So I would suggest submitting this test in a separate patch before this one after removing this section. Then add this section the test in this patch or make a new test for setAttribute("viewBox").
Comment 18 Nikolas Zimmermann 2019-09-05 14:53:31 PDT
(In reply to Said Abou-Hallawa from comment #17)
> Comment on attachment 378072 [details]
> Patch
> 
> onco -> once
> does not re-evaluates -> does not re-evaluate
Sorry for the typos, I will make sure to re-read the ChangeLog next time before submitting.
 
> > LayoutTests/ChangeLog:22
> > +        Verify that dynamic updates to the <view> element in the external SVG, are reflect in the SVGViewSpec API as well (SVGSVGElement::currentView).
> 
> This test is great but I think it deserves a separate patch because most of
> it is not related to this patch and can pass without it.
Fair enough, I will split it into a separated ticket.
 
> 
> > LayoutTests/svg/dom/SVGViewSpec-multiple-views.html:124
> > +    iframeElement.contentDocument.documentElement.getElementById("view2").setAttribute("viewBox", "10 10 30 30");
> > +
> > +    debug("");
> > +    debug("Check viewBox value after modification");
> > +    shouldBe("currentView.viewBox.baseVal.x", "10");
> > +    shouldBe("currentView.viewBox.baseVal.y", "10");
> > +    shouldBe("currentView.viewBox.baseVal.width", "30");
> > +    shouldBe("currentView.viewBox.baseVal.height", "30");
> > +    shouldBeEqualToString("currentView.viewBoxString", "10 10 30 30");
> 
> This section is the only one that calls setAttribute("viewBox"). So I think
> the rest of this test can pass without this patch. I guess this is because
> of the missing SVGViewElement::svgAttributeChanged().
Sure! The intention of the test was to convince myself, that the loading of external SVGs with fragment identifiers works as intended (no reloads, only scrollToAnchor() calls).

> So I would suggest submitting this test in a separate patch before this one
> after removing this section. Then add this section the test in this patch or
> make a new test for setAttribute("viewBox").

Okay, will take care of this tomorrow. Thanks for the quick review!
Comment 19 Nikolas Zimmermann 2019-09-06 00:57:47 PDT
(In reply to Nikolas Zimmermann from comment #18)
> > This test is great but I think it deserves a separate patch because most of
> > it is not related to this patch and can pass without it.
> Fair enough, I will split it into a separated ticket.

Filed https://bugs.webkit.org/show_bug.cgi?id=201536.
Will update this patch once the ticket is done.

P.S. Whom shall I mail to regain commiter rights? My Subversion account is disabled for sure. For reviewer status it is too early, still need to fix a few more issues and do unofficial reviews :-)
Comment 20 Nikolas Zimmermann 2019-09-06 08:23:36 PDT
(In reply to Nikolas Zimmermann from comment #19)
> P.S. Whom shall I mail to regain commiter rights? My Subversion account is
> disabled for sure. For reviewer status it is too early, still need to fix a
> few more issues and do unofficial reviews :-)
Never mind, I found all information on https://webkit.org/commit-and-review-policy/.
Comment 21 Nikolas Zimmermann 2019-09-10 13:35:49 PDT
Will upload a new patch tomorrow morning, now that the SVGViewSpec test landed.
Comment 22 Nikolas Zimmermann 2019-09-10 14:16:55 PDT
Created attachment 378490 [details]
Patch
Comment 23 Said Abou-Hallawa 2019-09-12 10:00:25 PDT
Comment on attachment 378490 [details]
Patch

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

> Source/WebCore/svg/SVGSVGElement.cpp:671
> +                ASSERT(rootElement->m_currentViewElement->targetElement());
> +                ASSERT(rootElement->m_currentViewElement->targetElement() == rootElement);

I think the second assertion is sufficient since at this point we are sure rootElement != nullptr.

> Source/WebCore/svg/SVGSVGElement.cpp:678
> +            if (!rootElement->m_currentViewElement || rootElement->m_currentViewElement != viewElement)

The first clause is not needed. We know that viewElement != nullptr so if rootElement->m_currentViewElement == nullptr, rootElement->m_currentViewElement != viewElement will be true.

> Source/WebCore/svg/SVGSVGElement.cpp:680
> +            rootElement->m_currentViewElement->setTargetElement(*rootElement);

I think this statement should be moved under the previous if-statement. If we are not setting rootElement->m_currentViewElement to a new value, then the target element of the rootElement->m_currentViewElement should be equal to rootElement. In fact this what we assert a few lines above.

> Source/WebCore/svg/SVGSVGElement.h:164
> +    WeakPtr<SVGViewElement> m_currentViewElement { nullptr };

Why is this a WeakPtr? My understanding is SVGSVGElement should own its current view so there should an ownership relation from SVGSVGElement to SVGViewElement. Even in the new code, SVGSVGElement is the one that controls the life cycle of both SVGSVGElement::m_currentViewElement and SVGViewElement::m_targetElement.

SVGSVGElement::m_currentViewElement is changed here:

    rootElement->m_currentViewElement = makeWeakPtr(viewElement); 

SVGViewElement::m_targetElement is changed here:

    rootElement->m_currentViewElement->resetTargetElement();

and

    rootElement->m_currentViewElement->setTargetElement(*rootElement);

On contrary to this SVGViewElement does not change any of these pointers. So I think this should be RefPtr while SVGViewElement::m_targetElement should stay WeakPtr.
Comment 24 Nikolas Zimmermann 2019-09-13 03:38:05 PDT
(In reply to Said Abou-Hallawa from comment #23)
> Comment on attachment 378490 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=378490&action=review
> 
> > Source/WebCore/svg/SVGSVGElement.cpp:671
> > +                ASSERT(rootElement->m_currentViewElement->targetElement());
> > +                ASSERT(rootElement->m_currentViewElement->targetElement() == rootElement);
> 
> I think the second assertion is sufficient since at this point we are sure
> rootElement != nullptr.
Agreed, that alone is enough to be sure that targetElement() was null if the assertion fires.

> > Source/WebCore/svg/SVGSVGElement.cpp:678
> > +            if (!rootElement->m_currentViewElement || rootElement->m_currentViewElement != viewElement)
> 
> The first clause is not needed. We know that viewElement != nullptr so if
> rootElement->m_currentViewElement == nullptr,
> rootElement->m_currentViewElement != viewElement will be true.
Sure, I just found it easier to read, but I can change it you like, I do not have a strong opinion.
 
> > Source/WebCore/svg/SVGSVGElement.cpp:680
> > +            rootElement->m_currentViewElement->setTargetElement(*rootElement);
> 
> I think this statement should be moved under the previous if-statement. If
> we are not setting rootElement->m_currentViewElement to a new value, then
> the target element of the rootElement->m_currentViewElement should be equal
> to rootElement. In fact this what we assert a few lines above.
Good catch, that was the initial intention and got lost in refactoring.
 
> > Source/WebCore/svg/SVGSVGElement.h:164
> > +    WeakPtr<SVGViewElement> m_currentViewElement { nullptr };
> 
> Why is this a WeakPtr? My understanding is SVGSVGElement should own its
> current view so there should an ownership relation from SVGSVGElement to
> SVGViewElement. Even in the new code, SVGSVGElement is the one that controls
> the life cycle of both SVGSVGElement::m_currentViewElement and
> SVGViewElement::m_targetElement.
> 
> SVGSVGElement::m_currentViewElement is changed here:
> 
>     rootElement->m_currentViewElement = makeWeakPtr(viewElement); 
> 
> SVGViewElement::m_targetElement is changed here:
> 
>     rootElement->m_currentViewElement->resetTargetElement();
> 
> and
> 
>     rootElement->m_currentViewElement->setTargetElement(*rootElement);
> 
> On contrary to this SVGViewElement does not change any of these pointers. So
> I think this should be RefPtr while SVGViewElement::m_targetElement should
> stay WeakPtr.
I initially chose WeakPtr for both to a) avoid dangling pointers and b) do not potentially introduce refcounting cycles. But I agree there is no risk in changing to RefPtr and it clarifies the ownership situation.

I will make the changes and upload a new patch, thanks Said!
Feels good to receive valuable comments! :-)
Comment 25 Nikolas Zimmermann 2019-09-13 04:21:01 PDT
Created attachment 378722 [details]
Patch
Comment 26 EWS 2019-09-13 10:36:39 PDT
Comment on attachment 378722 [details]
Patch

Rejecting attachment 378722 [details] from commit-queue.

zimmermann@kde.org does not have committer permissions according to https://trac.webkit.org/browser/trunk/Tools/Scripts/webkitpy/common/config/contributors.json.

- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.

- If you have committer rights please correct the error in Tools/Scripts/webkitpy/common/config/contributors.json by adding yourself to the file (no review needed).  The commit-queue restarts itself every 2 hours.  After restart the commit-queue will correctly respect your committer rights.
Comment 27 Nikolas Zimmermann 2019-09-13 10:38:44 PDT
Thanks a lot Said.
Comment 28 WebKit Commit Bot 2019-09-13 11:21:20 PDT
Comment on attachment 378722 [details]
Patch

Clearing flags on attachment: 378722

Committed r249843: <https://trac.webkit.org/changeset/249843>
Comment 29 WebKit Commit Bot 2019-09-13 11:21:22 PDT
All reviewed patches have been landed.  Closing bug.
Comment 30 Radar WebKit Bug Importer 2019-09-13 11:22:38 PDT
<rdar://problem/55346015>