<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[214503] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/214503">214503</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2017-03-28 16:11:35 -0700 (Tue, 28 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Animated SVG images are not paused when outside viewport
https://bugs.webkit.org/show_bug.cgi?id=170155
&lt;rdar://problem/31288893&gt;

Reviewed by Antti Koivisto.

Source/WebCore:

Make sure animated SVG images get paused when outside the viewport,
similarly to what was already done for animated GIF images. Also
make sure they are paused when they no longer have any renderers
using them.

Tests: svg/animations/animated-svg-image-outside-viewport-paused.html
       svg/animations/animated-svg-image-removed-from-document-paused.html

* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::didAddClient):
Restart the animation whenever a new CachedImage client is added. This
will cause us the re-evaluate if the animation should run. The animation
will pause again if the new renderer is not inside the viewport.

(WebCore::CachedImage::animationAdvanced):
Add a flag to newImageAnimationFrameAvailable() so that the renderers can
let us know if we can pause the animation. Pause the animation if all no
renderer requires it (i.e. they are all outside the viewport, or there
are no renderers).

* loader/cache/CachedImageClient.h:
(WebCore::CachedImageClient::newImageAnimationFrameAvailable):
By default, the CachedImageClients allow pausing. Only renderer will
potentially prevent pausing if they are inside the viewport.

* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::isAnimating):
* platform/graphics/BitmapImage.h:
* platform/graphics/Image.h:
(WebCore::Image::isAnimating):
Add isAnimating() flag on Image for layout testing purposes.

* rendering/RenderElement.cpp:
(WebCore::RenderElement::newImageAnimationFrameAvailable):
Set canPause flag to true if the renderer is not inside the viewport.

(WebCore::RenderElement::repaintForPausedImageAnimationsIfNeeded):
Call startAnimation() if the renderer is now visible to resume SVG
animations. Repainting is enough for GIF animations but not for SVG
animations, we have to explicitly resume them.

* rendering/RenderElement.h:
* rendering/RenderView.cpp:
(WebCore::RenderView::addRendererWithPausedImageAnimations):
(WebCore::RenderView::removeRendererWithPausedImageAnimations):
(WebCore::RenderView::resumePausedImageAnimationsIfNeeded):
* rendering/RenderView.h:
Store CachedImages with the renderers that have paused animations.
This is required for SVG where we need to explicitly resume the
animation on the CachedImage when the renderer becomes visible
again. Having access to the Image will also allow us to do smarter
visibility checks in RenderElement's shouldRepaintForImageAnimation(),
in the future.

* svg/SVGSVGElement.cpp:
(WebCore::SVGSVGElement::hasActiveAnimation):
* svg/SVGSVGElement.h:
Add hasActiveAnimation() method.

* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::startAnimation):
Check that animations are paused before starting them. This avoid
jumping due to unnecessary calls to rootElement-&gt;setCurrentTime(0).

(WebCore::SVGImage::isAnimating):
Add isAnimating() method for layout tests purposes.

* svg/graphics/SVGImage.h:
* svg/graphics/SVGImageClients.h:
Call animationAdvanced() on the observer instead of the generic
changedInRect() when the SVGImage is animating. This way, we go
through the same code path as GIF animations and we end up calling
CachedImage::animationAdvanced() which calls newImageAnimationFrameAvailable()
on RenderElement, which determines if the animation should keep
running or not.

* testing/Internals.cpp:
(WebCore::Internals::isImageAnimating):
* testing/Internals.h:
* testing/Internals.idl:
Add layout testing infrastructure.

LayoutTests:

Add layout test coverage.

* platform/mac-wk1/TestExpectations:
* svg/animations/animated-svg-image-outside-viewport-paused-expected.txt: Added.
* svg/animations/animated-svg-image-outside-viewport-paused.html: Added.
* svg/animations/animated-svg-image-removed-from-document-paused-expected.txt: Added.
* svg/animations/animated-svg-image-removed-from-document-paused.html: Added.
* svg/animations/resources/smilAnimation.svg: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformmacwk1TestExpectations">trunk/LayoutTests/platform/mac-wk1/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedImagecpp">trunk/Source/WebCore/loader/cache/CachedImage.cpp</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedImageClienth">trunk/Source/WebCore/loader/cache/CachedImageClient.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsBitmapImagecpp">trunk/Source/WebCore/platform/graphics/BitmapImage.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsBitmapImageh">trunk/Source/WebCore/platform/graphics/BitmapImage.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageh">trunk/Source/WebCore/platform/graphics/Image.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementcpp">trunk/Source/WebCore/rendering/RenderElement.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementh">trunk/Source/WebCore/rendering/RenderElement.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderViewcpp">trunk/Source/WebCore/rendering/RenderView.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderViewh">trunk/Source/WebCore/rendering/RenderView.h</a></li>
<li><a href="#trunkSourceWebCorerenderingstyleStyleCachedImagecpp">trunk/Source/WebCore/rendering/style/StyleCachedImage.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGSVGElementcpp">trunk/Source/WebCore/svg/SVGSVGElement.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGSVGElementh">trunk/Source/WebCore/svg/SVGSVGElement.h</a></li>
<li><a href="#trunkSourceWebCoresvggraphicsSVGImagecpp">trunk/Source/WebCore/svg/graphics/SVGImage.cpp</a></li>
<li><a href="#trunkSourceWebCoresvggraphicsSVGImageh">trunk/Source/WebCore/svg/graphics/SVGImage.h</a></li>
<li><a href="#trunkSourceWebCoresvggraphicsSVGImageClientsh">trunk/Source/WebCore/svg/graphics/SVGImageClients.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalscpp">trunk/Source/WebCore/testing/Internals.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsh">trunk/Source/WebCore/testing/Internals.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsidl">trunk/Source/WebCore/testing/Internals.idl</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestssvganimationsanimatedsvgimageoutsideviewportpausedexpectedtxt">trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused-expected.txt</a></li>
<li><a href="#trunkLayoutTestssvganimationsanimatedsvgimageoutsideviewportpausedhtml">trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused.html</a></li>
<li><a href="#trunkLayoutTestssvganimationsanimatedsvgimageremovedfromdocumentpausedexpectedtxt">trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused-expected.txt</a></li>
<li><a href="#trunkLayoutTestssvganimationsanimatedsvgimageremovedfromdocumentpausedhtml">trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused.html</a></li>
<li><a href="#trunkLayoutTestssvganimationsresourcessmilAnimationsvg">trunk/LayoutTests/svg/animations/resources/smilAnimation.svg</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/LayoutTests/ChangeLog        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2017-03-28  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Animated SVG images are not paused when outside viewport
+        https://bugs.webkit.org/show_bug.cgi?id=170155
+        &lt;rdar://problem/31288893&gt;
+
+        Reviewed by Antti Koivisto.
+
+        Add layout test coverage.
+
+        * platform/mac-wk1/TestExpectations:
+        * svg/animations/animated-svg-image-outside-viewport-paused-expected.txt: Added.
+        * svg/animations/animated-svg-image-outside-viewport-paused.html: Added.
+        * svg/animations/animated-svg-image-removed-from-document-paused-expected.txt: Added.
+        * svg/animations/animated-svg-image-removed-from-document-paused.html: Added.
+        * svg/animations/resources/smilAnimation.svg: Added.
+
</ins><span class="cx"> 2017-03-28  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Missing render tree position invalidation when tearing down renderers for display:contents subtree
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmacwk1TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac-wk1/TestExpectations        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -123,6 +123,8 @@
</span><span class="cx"> fast/images/animated-gif-body-outside-viewport.html [ Skip ]
</span><span class="cx"> fast/images/animated-gif-window-resizing.html [ Skip ]
</span><span class="cx"> fast/images/animated-gif-zooming.html [ Skip ]
</span><ins>+svg/animations/animated-svg-image-outside-viewport-paused.html [ Skip ]
+svg/animations/animated-svg-image-removed-from-document-paused.html [ Skip ]
</ins><span class="cx"> 
</span><span class="cx"> # WK1 uses the native scrollview for scrolling by page.
</span><span class="cx"> scrollbars/scrolling-backward-by-page-accounting-bottom-fixed-elements-on-keyboard-spacebar.html
</span></span></pre></div>
<a id="trunkLayoutTestssvganimationsanimatedsvgimageoutsideviewportpausedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused-expected.txt (0 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused-expected.txt                                (rev 0)
+++ trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused-expected.txt        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+Tests that animated SVG images are paused when outside the viewport.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Initially outside the viewport
+PASS internals.isImageAnimating(image) is false
+Scrolling animation into view
+PASS internals.isImageAnimating(image) became true
+Scrolling animation outside view again
+PASS internals.isImageAnimating(image) became false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestssvganimationsanimatedsvgimageoutsideviewportpausedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused.html (0 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused.html                                (rev 0)
+++ trunk/LayoutTests/svg/animations/animated-svg-image-outside-viewport-paused.html        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+description(&quot;Tests that animated SVG images are paused when outside the viewport.&quot;);
+jsTestIsAsync = true;
+
+onload = function() {
+    image = document.querySelector(&quot;img&quot;);
+
+    setTimeout(function() {
+        debug(&quot;Initially outside the viewport&quot;);
+        shouldBeFalse(&quot;internals.isImageAnimating(image)&quot;);
+
+        debug(&quot;Scrolling animation into view&quot;);
+        internals.scrollElementToRect(image, 0, 0, 300, 300);
+        shouldBecomeEqual(&quot;internals.isImageAnimating(image)&quot;, &quot;true&quot;, function() {
+            debug(&quot;Scrolling animation outside view again&quot;);
+            scroll(0, 0);
+            shouldBecomeEqual(&quot;internals.isImageAnimating(image)&quot;, &quot;false&quot;, finishJSTest);
+        });
+    }, 30);
+}
+&lt;/script&gt;
+&lt;div style=&quot;position: relative; width: 1600px; height: 2400px;&quot;&gt;
+&lt;img src=&quot;resources/smilAnimation.svg&quot; style=&quot;position:absolute; left: 600px; top: 800px;&quot;&gt;
+&lt;/div&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestssvganimationsanimatedsvgimageremovedfromdocumentpausedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused-expected.txt (0 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused-expected.txt                                (rev 0)
+++ trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused-expected.txt        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+Tests that animated SVG images are paused when removed from the document.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS internals.isImageAnimating(imageA) is true
+PASS internals.isImageAnimating(imageB) is true
+imageA.remove()
+PASS internals.isImageAnimating(imageB) is true
+PASS internals.isImageAnimating(imageB) is true
+imageB.remove()
+PASS internals.isImageAnimating(imageA) is false
+PASS internals.isImageAnimating(imageB) is false
+document.body.appendChild(imageA)
+PASS internals.isImageAnimating(imageA) is true
+document.body.appendChild(imageB)
+PASS internals.isImageAnimating(imageB) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE

</ins></span></pre></div>
<a id="trunkLayoutTestssvganimationsanimatedsvgimageremovedfromdocumentpausedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused.html (0 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused.html                                (rev 0)
+++ trunk/LayoutTests/svg/animations/animated-svg-image-removed-from-document-paused.html        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;img id=&quot;a&quot; src=&quot;resources/smilAnimation.svg&quot;&gt;
+&lt;img id=&quot;b&quot; src=&quot;resources/smilAnimation.svg&quot;&gt;
+&lt;script&gt;
+description(&quot;Tests that animated SVG images are paused when removed from the document.&quot;);
+jsTestIsAsync = true;
+
+// Both images will use the same underlying SVGImage.
+const imageA = document.getElementById(&quot;a&quot;);
+const imageB = document.getElementById(&quot;b&quot;);
+
+onload = function() {
+    shouldBeTrue(&quot;internals.isImageAnimating(imageA)&quot;);
+    shouldBeTrue(&quot;internals.isImageAnimating(imageB)&quot;);
+
+    setTimeout(function() {
+        evalAndLog(&quot;imageA.remove()&quot;);
+        shouldBeTrue(&quot;internals.isImageAnimating(imageB)&quot;);
+
+        setTimeout(function() {
+            shouldBeTrue(&quot;internals.isImageAnimating(imageB)&quot;);
+            evalAndLog(&quot;imageB.remove()&quot;);
+            setTimeout(function() {
+                shouldBeFalse(&quot;internals.isImageAnimating(imageA)&quot;);
+                shouldBeFalse(&quot;internals.isImageAnimating(imageB)&quot;);
+
+                evalAndLog(&quot;document.body.appendChild(imageA)&quot;);
+                document.body.offsetWidth; // Force layout.
+                shouldBeTrue(&quot;internals.isImageAnimating(imageA)&quot;);
+                evalAndLog(&quot;document.body.appendChild(imageB)&quot;);
+                document.body.offsetWidth; // Force layout.
+                shouldBeTrue(&quot;internals.isImageAnimating(imageB)&quot;);
+
+                finishJSTest();
+            }, 30);
+        }, 30);
+    }, 30);
+}
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestssvganimationsresourcessmilAnimationsvg"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/svg/animations/resources/smilAnimation.svg (0 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/svg/animations/resources/smilAnimation.svg                                (rev 0)
+++ trunk/LayoutTests/svg/animations/resources/smilAnimation.svg        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+&lt;svg width=&quot;200&quot; height=&quot;100&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot;&gt;
+    &lt;rect width=&quot;100&quot; height=&quot;100&quot; fill=&quot;green&quot;&gt;
+        &lt;animate attributeName=&quot;x&quot; values=&quot;0; 100; 0&quot; dur=&quot;1s&quot; repeatCount=&quot;indefinite&quot;&gt;&lt;/animate&gt;
+    &lt;/rect&gt;
+&lt;/svg&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/ChangeLog        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -1,3 +1,93 @@
</span><ins>+2017-03-28  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Animated SVG images are not paused when outside viewport
+        https://bugs.webkit.org/show_bug.cgi?id=170155
+        &lt;rdar://problem/31288893&gt;
+
+        Reviewed by Antti Koivisto.
+
+        Make sure animated SVG images get paused when outside the viewport,
+        similarly to what was already done for animated GIF images. Also
+        make sure they are paused when they no longer have any renderers
+        using them.
+
+        Tests: svg/animations/animated-svg-image-outside-viewport-paused.html
+               svg/animations/animated-svg-image-removed-from-document-paused.html
+
+        * loader/cache/CachedImage.cpp:
+        (WebCore::CachedImage::didAddClient):
+        Restart the animation whenever a new CachedImage client is added. This
+        will cause us the re-evaluate if the animation should run. The animation
+        will pause again if the new renderer is not inside the viewport.
+
+        (WebCore::CachedImage::animationAdvanced):
+        Add a flag to newImageAnimationFrameAvailable() so that the renderers can
+        let us know if we can pause the animation. Pause the animation if all no
+        renderer requires it (i.e. they are all outside the viewport, or there
+        are no renderers).
+
+        * loader/cache/CachedImageClient.h:
+        (WebCore::CachedImageClient::newImageAnimationFrameAvailable):
+        By default, the CachedImageClients allow pausing. Only renderer will
+        potentially prevent pausing if they are inside the viewport.
+
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::isAnimating):
+        * platform/graphics/BitmapImage.h:
+        * platform/graphics/Image.h:
+        (WebCore::Image::isAnimating):
+        Add isAnimating() flag on Image for layout testing purposes.
+
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::newImageAnimationFrameAvailable):
+        Set canPause flag to true if the renderer is not inside the viewport.
+
+        (WebCore::RenderElement::repaintForPausedImageAnimationsIfNeeded):
+        Call startAnimation() if the renderer is now visible to resume SVG
+        animations. Repainting is enough for GIF animations but not for SVG
+        animations, we have to explicitly resume them.
+
+        * rendering/RenderElement.h:
+        * rendering/RenderView.cpp:
+        (WebCore::RenderView::addRendererWithPausedImageAnimations):
+        (WebCore::RenderView::removeRendererWithPausedImageAnimations):
+        (WebCore::RenderView::resumePausedImageAnimationsIfNeeded):
+        * rendering/RenderView.h:
+        Store CachedImages with the renderers that have paused animations.
+        This is required for SVG where we need to explicitly resume the
+        animation on the CachedImage when the renderer becomes visible
+        again. Having access to the Image will also allow us to do smarter
+        visibility checks in RenderElement's shouldRepaintForImageAnimation(),
+        in the future.
+
+        * svg/SVGSVGElement.cpp:
+        (WebCore::SVGSVGElement::hasActiveAnimation):
+        * svg/SVGSVGElement.h:
+        Add hasActiveAnimation() method.
+
+        * svg/graphics/SVGImage.cpp:
+        (WebCore::SVGImage::startAnimation):
+        Check that animations are paused before starting them. This avoid
+        jumping due to unnecessary calls to rootElement-&gt;setCurrentTime(0).
+
+        (WebCore::SVGImage::isAnimating):
+        Add isAnimating() method for layout tests purposes.
+
+        * svg/graphics/SVGImage.h:
+        * svg/graphics/SVGImageClients.h:
+        Call animationAdvanced() on the observer instead of the generic
+        changedInRect() when the SVGImage is animating. This way, we go
+        through the same code path as GIF animations and we end up calling
+        CachedImage::animationAdvanced() which calls newImageAnimationFrameAvailable()
+        on RenderElement, which determines if the animation should keep
+        running or not.
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::isImageAnimating):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+        Add layout testing infrastructure.
+
</ins><span class="cx"> 2017-03-28  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Missing render tree position invalidation when tearing down renderers for display:contents subtree
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedImage.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedImage.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/loader/cache/CachedImage.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -117,6 +117,9 @@
</span><span class="cx">     if (m_image &amp;&amp; !m_image-&gt;isNull())
</span><span class="cx">         static_cast&lt;CachedImageClient&amp;&gt;(client).imageChanged(this);
</span><span class="cx"> 
</span><ins>+    if (m_image)
+        m_image-&gt;startAnimation();
+
</ins><span class="cx">     CachedResource::didAddClient(client);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -514,9 +517,19 @@
</span><span class="cx"> {
</span><span class="cx">     if (!image || image != m_image)
</span><span class="cx">         return;
</span><ins>+
+    bool shouldPauseAnimation = true;
+
</ins><span class="cx">     CachedResourceClientWalker&lt;CachedImageClient&gt; clientWalker(m_clients);
</span><del>-    while (CachedImageClient* client = clientWalker.next())
-        client-&gt;newImageAnimationFrameAvailable(*this);
</del><ins>+    while (CachedImageClient* client = clientWalker.next()) {
+        bool canPause = false;
+        client-&gt;newImageAnimationFrameAvailable(*this, canPause);
+        if (!canPause)
+            shouldPauseAnimation = false;
+    }
+
+    if (shouldPauseAnimation)
+        m_image-&gt;stopAnimation();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CachedImage::changedInRect(const Image* image, const IntRect* rect)
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedImageClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedImageClient.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedImageClient.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/loader/cache/CachedImageClient.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx">     virtual void imageChanged(CachedImage*, const IntRect* = nullptr) { }
</span><span class="cx"> 
</span><span class="cx">     // Called when GIF animation progresses.
</span><del>-    virtual void newImageAnimationFrameAvailable(CachedImage&amp; image) { imageChanged(&amp;image); }
</del><ins>+    virtual void newImageAnimationFrameAvailable(CachedImage&amp; image, bool&amp; canPause) { imageChanged(&amp;image); canPause = true; }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -406,6 +406,11 @@
</span><span class="cx">     LOG(Images, &quot;BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]&quot;, __FUNCTION__, this, sourceURL().utf8().data(), m_currentFrame);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BitmapImage::isAnimating() const
+{
+    return !!m_frameTimer;
+}
+
</ins><span class="cx"> void BitmapImage::stopAnimation()
</span><span class="cx"> {
</span><span class="cx">     // This timer is used to animate all occurrences of this image. Don't invalidate
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsBitmapImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/BitmapImage.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -169,6 +169,7 @@
</span><span class="cx">     StartAnimationStatus internalStartAnimation();
</span><span class="cx">     void advanceAnimation();
</span><span class="cx">     void internalAdvanceAnimation();
</span><ins>+    bool isAnimating() const final;
</ins><span class="cx"> 
</span><span class="cx">     // It may look unusual that there is no start animation call as public API. This is because
</span><span class="cx">     // we start and stop animating lazily. Animation begins whenever someone draws the image. It will
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Image.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Image.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/platform/graphics/Image.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -131,6 +131,7 @@
</span><span class="cx">     virtual void stopAnimation() {}
</span><span class="cx">     virtual void resetAnimation() {}
</span><span class="cx">     virtual void newFrameNativeImageAvailableAtIndex(size_t) { }
</span><ins>+    virtual bool isAnimating() const { return false; }
</ins><span class="cx">     
</span><span class="cx">     // Typically the CachedImage that owns us.
</span><span class="cx">     ImageObserver* imageObserver() const { return m_imageObserver; }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -1494,21 +1494,19 @@
</span><span class="cx">     ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderElement::newImageAnimationFrameAvailable(CachedImage&amp; image)
</del><ins>+void RenderElement::newImageAnimationFrameAvailable(CachedImage&amp; image, bool&amp; canPause)
</ins><span class="cx"> {
</span><span class="cx">     auto&amp; frameView = view().frameView();
</span><span class="cx">     auto visibleRect = frameView.windowToContents(frameView.windowClipRect());
</span><span class="cx">     if (!shouldRepaintForImageAnimation(*this, visibleRect)) {
</span><del>-        // FIXME: It would be better to pass the image along with the renderer
-        // so that we can be smarter about detecting if the image is inside the
-        // viewport in repaintForPausedImageAnimationsIfNeeded().
-        view().addRendererWithPausedImageAnimations(*this);
</del><ins>+        view().addRendererWithPausedImageAnimations(*this, image);
+        canPause = true;
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     imageChanged(&amp;image);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool RenderElement::repaintForPausedImageAnimationsIfNeeded(const IntRect&amp; visibleRect)
</del><ins>+bool RenderElement::repaintForPausedImageAnimationsIfNeeded(const IntRect&amp; visibleRect, CachedImage&amp; cachedImage)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_hasPausedImageAnimations);
</span><span class="cx">     if (!shouldRepaintForImageAnimation(*this, visibleRect))
</span><span class="lines">@@ -1516,6 +1514,9 @@
</span><span class="cx"> 
</span><span class="cx">     repaint();
</span><span class="cx"> 
</span><ins>+    if (auto* image = cachedImage.image())
+        image-&gt;startAnimation();
+
</ins><span class="cx">     // For directly-composited animated GIFs it does not suffice to call repaint() to resume animation. We need to mark the image as changed.
</span><span class="cx">     if (is&lt;RenderBoxModelObject&gt;(*this))
</span><span class="cx">         downcast&lt;RenderBoxModelObject&gt;(*this).contentChanged(ImageChanged);
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/rendering/RenderElement.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -195,7 +195,7 @@
</span><span class="cx">     void setVisibleInViewportState(VisibleInViewportState);
</span><span class="cx">     virtual void visibleInViewportStateChanged();
</span><span class="cx"> 
</span><del>-    bool repaintForPausedImageAnimationsIfNeeded(const IntRect&amp; visibleRect);
</del><ins>+    bool repaintForPausedImageAnimationsIfNeeded(const IntRect&amp; visibleRect, CachedImage&amp;);
</ins><span class="cx">     bool hasPausedImageAnimations() const { return m_hasPausedImageAnimations; }
</span><span class="cx">     void setHasPausedImageAnimations(bool b) { m_hasPausedImageAnimations = b; }
</span><span class="cx"> 
</span><span class="lines">@@ -317,7 +317,7 @@
</span><span class="cx">     std::unique_ptr&lt;RenderStyle&gt; computeFirstLineStyle() const;
</span><span class="cx">     void invalidateCachedFirstLineStyle();
</span><span class="cx"> 
</span><del>-    void newImageAnimationFrameAvailable(CachedImage&amp;) final;
</del><ins>+    void newImageAnimationFrameAvailable(CachedImage&amp;, bool&amp; canPause) final;
</ins><span class="cx"> 
</span><span class="cx">     bool getLeadingCorner(FloatPoint&amp; output, bool&amp; insideFixed) const;
</span><span class="cx">     bool getTrailingCorner(FloatPoint&amp; output, bool&amp; insideFixed) const;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderView.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderView.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/rendering/RenderView.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -1395,14 +1395,16 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderView::addRendererWithPausedImageAnimations(RenderElement&amp; renderer)
</del><ins>+void RenderView::addRendererWithPausedImageAnimations(RenderElement&amp; renderer, CachedImage&amp; image)
</ins><span class="cx"> {
</span><del>-    if (renderer.hasPausedImageAnimations()) {
-        ASSERT(m_renderersWithPausedImageAnimation.contains(&amp;renderer));
-        return;
-    }
</del><ins>+    ASSERT(!renderer.hasPausedImageAnimations() || m_renderersWithPausedImageAnimation.contains(&amp;renderer));
+
</ins><span class="cx">     renderer.setHasPausedImageAnimations(true);
</span><del>-    m_renderersWithPausedImageAnimation.add(&amp;renderer);
</del><ins>+    auto&amp; images = m_renderersWithPausedImageAnimation.ensure(&amp;renderer, [] {
+        return Vector&lt;CachedImage*&gt;();
+    }).iterator-&gt;value;
+    if (!images.contains(&amp;image))
+        images.append(&amp;image);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderView::removeRendererWithPausedImageAnimations(RenderElement&amp; renderer)
</span><span class="lines">@@ -1414,15 +1416,35 @@
</span><span class="cx">     m_renderersWithPausedImageAnimation.remove(&amp;renderer);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void RenderView::removeRendererWithPausedImageAnimations(RenderElement&amp; renderer, CachedImage&amp; image)
+{
+    ASSERT(renderer.hasPausedImageAnimations());
+
+    auto it = m_renderersWithPausedImageAnimation.find(&amp;renderer);
+    ASSERT(it != m_renderersWithPausedImageAnimation.end());
+
+    auto&amp; images = it-&gt;value;
+    if (!images.contains(&amp;image))
+        return;
+
+    if (images.size() == 1)
+        removeRendererWithPausedImageAnimations(renderer);
+    else
+        images.removeFirst(&amp;image);
+}
+
</ins><span class="cx"> void RenderView::resumePausedImageAnimationsIfNeeded(IntRect visibleRect)
</span><span class="cx"> {
</span><del>-    Vector&lt;RenderElement*, 10&gt; toRemove;
-    for (auto* renderer : m_renderersWithPausedImageAnimation) {
-        if (renderer-&gt;repaintForPausedImageAnimationsIfNeeded(visibleRect))
-            toRemove.append(renderer);
</del><ins>+    Vector&lt;std::pair&lt;RenderElement*, CachedImage*&gt;, 10&gt; toRemove;
+    for (auto&amp; it : m_renderersWithPausedImageAnimation) {
+        auto* renderer = it.key;
+        for (auto* image : it.value) {
+            if (renderer-&gt;repaintForPausedImageAnimationsIfNeeded(visibleRect, *image))
+                toRemove.append(std::make_pair(renderer, image));
+        }
</ins><span class="cx">     }
</span><del>-    for (auto&amp; renderer : toRemove)
-        removeRendererWithPausedImageAnimations(*renderer);
</del><ins>+    for (auto&amp; pair : toRemove)
+        removeRendererWithPausedImageAnimations(*pair.first, *pair.second);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RenderView::RepaintRegionAccumulator::RepaintRegionAccumulator(RenderView* view)
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderView.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderView.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/rendering/RenderView.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -229,8 +229,9 @@
</span><span class="cx">     void registerForVisibleInViewportCallback(RenderElement&amp;);
</span><span class="cx">     void unregisterForVisibleInViewportCallback(RenderElement&amp;);
</span><span class="cx">     void resumePausedImageAnimationsIfNeeded(IntRect visibleRect);
</span><del>-    void addRendererWithPausedImageAnimations(RenderElement&amp;);
</del><ins>+    void addRendererWithPausedImageAnimations(RenderElement&amp;, CachedImage&amp;);
</ins><span class="cx">     void removeRendererWithPausedImageAnimations(RenderElement&amp;);
</span><ins>+    void removeRendererWithPausedImageAnimations(RenderElement&amp;, CachedImage&amp;);
</ins><span class="cx"> 
</span><span class="cx">     class RepaintRegionAccumulator {
</span><span class="cx">         WTF_MAKE_NONCOPYABLE(RepaintRegionAccumulator);
</span><span class="lines">@@ -389,7 +390,7 @@
</span><span class="cx">     bool m_inHitTesting { false };
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    HashSet&lt;RenderElement*&gt; m_renderersWithPausedImageAnimation;
</del><ins>+    HashMap&lt;RenderElement*, Vector&lt;CachedImage*&gt;&gt; m_renderersWithPausedImageAnimation;
</ins><span class="cx">     HashSet&lt;RenderElement*&gt; m_visibleInViewportRenderers;
</span><span class="cx">     Vector&lt;RefPtr&lt;RenderWidget&gt;&gt; m_protectedRenderWidgets;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingstyleStyleCachedImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/style/StyleCachedImage.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/style/StyleCachedImage.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/rendering/style/StyleCachedImage.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;CSSImageValue.h&quot;
</span><span class="cx"> #include &quot;CachedImage.h&quot;
</span><span class="cx"> #include &quot;RenderElement.h&quot;
</span><ins>+#include &quot;RenderView.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -186,6 +187,10 @@
</span><span class="cx">     if (!m_cachedImage)
</span><span class="cx">         return;
</span><span class="cx">     ASSERT(renderer);
</span><ins>+
+    if (renderer-&gt;hasPausedImageAnimations())
+        renderer-&gt;view().removeRendererWithPausedImageAnimations(*renderer, *m_cachedImage);
+
</ins><span class="cx">     m_cachedImage-&gt;removeClient(*renderer);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGSVGElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGSVGElement.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGSVGElement.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/svg/SVGSVGElement.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -507,6 +507,11 @@
</span><span class="cx">     return m_timeContainer-&gt;isPaused();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool SVGSVGElement::hasActiveAnimation() const
+{
+    return m_timeContainer-&gt;isActive();
+}
+
</ins><span class="cx"> float SVGSVGElement::getCurrentTime() const
</span><span class="cx"> {
</span><span class="cx">     return narrowPrecisionToFloat(m_timeContainer-&gt;elapsed().value());
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGSVGElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGSVGElement.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGSVGElement.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/svg/SVGSVGElement.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -85,6 +85,7 @@
</span><span class="cx">     void pauseAnimations();
</span><span class="cx">     void unpauseAnimations();
</span><span class="cx">     bool animationsPaused() const;
</span><ins>+    bool hasActiveAnimation() const;
</ins><span class="cx"> 
</span><span class="cx">     float getCurrentTime() const;
</span><span class="cx">     void setCurrentTime(float);
</span></span></pre></div>
<a id="trunkSourceWebCoresvggraphicsSVGImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/graphics/SVGImage.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/graphics/SVGImage.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/svg/graphics/SVGImage.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -374,7 +374,7 @@
</span><span class="cx"> void SVGImage::startAnimation()
</span><span class="cx"> {
</span><span class="cx">     SVGSVGElement* rootElement = this-&gt;rootElement();
</span><del>-    if (!rootElement)
</del><ins>+    if (!rootElement || !rootElement-&gt;animationsPaused())
</ins><span class="cx">         return;
</span><span class="cx">     rootElement-&gt;unpauseAnimations();
</span><span class="cx">     rootElement-&gt;setCurrentTime(0);
</span><span class="lines">@@ -393,6 +393,14 @@
</span><span class="cx">     stopAnimation();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool SVGImage::isAnimating() const
+{
+    SVGSVGElement* rootElement = this-&gt;rootElement();
+    if (!rootElement)
+        return false;
+    return rootElement-&gt;hasActiveAnimation();
+}
+
</ins><span class="cx"> void SVGImage::reportApproximateMemoryCost() const
</span><span class="cx"> {
</span><span class="cx">     Document* document = m_page-&gt;mainFrame().document();
</span></span></pre></div>
<a id="trunkSourceWebCoresvggraphicsSVGImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/graphics/SVGImage.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/graphics/SVGImage.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/svg/graphics/SVGImage.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx">     void startAnimation() final;
</span><span class="cx">     void stopAnimation() final;
</span><span class="cx">     void resetAnimation() final;
</span><ins>+    bool isAnimating() const final;
</ins><span class="cx"> 
</span><span class="cx"> #if USE(CAIRO)
</span><span class="cx">     NativeImagePtr nativeImageForCurrentFrame(const GraphicsContext* = nullptr) final;
</span></span></pre></div>
<a id="trunkSourceWebCoresvggraphicsSVGImageClientsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/graphics/SVGImageClients.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/graphics/SVGImageClients.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/svg/graphics/SVGImageClients.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><span class="cx"> #include &quot;EmptyClients.h&quot;
</span><ins>+#include &quot;SVGImage.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -52,8 +53,17 @@
</span><span class="cx">     void invalidateContentsAndRootView(const IntRect&amp; r) final
</span><span class="cx">     {
</span><span class="cx">         // If m_image-&gt;m_page is null, we're being destructed, don't fire changedInRect() in that case.
</span><del>-        if (m_image &amp;&amp; m_image-&gt;imageObserver() &amp;&amp; m_image-&gt;m_page)
-            m_image-&gt;imageObserver()-&gt;changedInRect(m_image, &amp;r);
</del><ins>+        if (!m_image || !m_image-&gt;m_page)
+            return;
+
+        auto* imageObserver = m_image-&gt;imageObserver();
+        if (!imageObserver)
+            return;
+
+        if (m_image-&gt;isAnimating())
+            imageObserver-&gt;animationAdvanced(m_image);
+        else
+            imageObserver-&gt;changedInRect(m_image, &amp;r);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     SVGImage* m_image;
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.cpp (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.cpp        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/testing/Internals.cpp        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -744,6 +744,19 @@
</span><span class="cx">     image-&gt;resetAnimation();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Internals::isImageAnimating(HTMLImageElement&amp; element)
+{
+    auto* cachedImage = element.cachedImage();
+    if (!cachedImage)
+        return false;
+
+    auto* image = cachedImage-&gt;image();
+    if (!image)
+        return false;
+
+    return image-&gt;isAnimating();
+}
+
</ins><span class="cx"> void Internals::setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement&amp; element, bool value)
</span><span class="cx"> {
</span><span class="cx">     auto* cachedImage = element.cachedImage();
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.h (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.h        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/testing/Internals.h        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -115,6 +115,7 @@
</span><span class="cx">     unsigned imageFrameIndex(HTMLImageElement&amp;);
</span><span class="cx">     void setImageFrameDecodingDuration(HTMLImageElement&amp;, float duration);
</span><span class="cx">     void resetImageAnimation(HTMLImageElement&amp;);
</span><ins>+    bool isImageAnimating(HTMLImageElement&amp;);
</ins><span class="cx">     void setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement&amp;, bool);
</span><span class="cx"> 
</span><span class="cx">     void clearPageCache();
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.idl (214502 => 214503)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.idl        2017-03-28 23:00:36 UTC (rev 214502)
+++ trunk/Source/WebCore/testing/Internals.idl        2017-03-28 23:11:35 UTC (rev 214503)
</span><span class="lines">@@ -244,6 +244,7 @@
</span><span class="cx">     unsigned long imageFrameIndex(HTMLImageElement element);
</span><span class="cx">     void setImageFrameDecodingDuration(HTMLImageElement element, unrestricted float duration);
</span><span class="cx">     void resetImageAnimation(HTMLImageElement element);
</span><ins>+    boolean isImageAnimating(HTMLImageElement element);
</ins><span class="cx">     void setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement element, boolean value);
</span><span class="cx"> 
</span><span class="cx">     readonly attribute InternalSettings settings;
</span></span></pre>
</div>
</div>

</body>
</html>