Title: [214561] trunk
Revision
214561
Author
cdu...@apple.com
Date
2017-03-29 13:54:21 -0700 (Wed, 29 Mar 2017)

Log Message

Animated SVG images are not paused in pages loaded in the background
https://bugs.webkit.org/show_bug.cgi?id=170043
<rdar://problem/31234412>

Reviewed by Simon Fraser.

Source/WebCore:

Animated SVG images are not paused in pages loaded in the background. We rely
on FrameView::isOffscreen() to stop images animations in background tab (See
logic in RenderElement's shouldRepaintForImageAnimation()). This works fine
if a tab is visble and then becomes hidden (i.e. by switching to another
tab). However, in the case where the tab gets loaded while in the background
(e.g. opening link in new background tab, or session restore), then the
animations would not be paused, due to FrameView::isOffscreen() erroneously
returning false in this case.

Normally, the following chain of events happens:
- Page is visible, we construct a main frame and its FrameView for loading
  the page. When a FrameView is constructed, we call FrameView::show() to
  make it visible. Then, if the page becomes non-visible, we call
  Page::setIsVisibleInternal(false) which calls FrameView::hide(). After
  that, FrameView::isOffscreen() correctly returns true because we properly
  called FrameView::hide().

However, when doing a load while the Page is hidden, the following was
happening:
- Page is not visible, we call Page::setIsVisibleInternal(false) which tries
  to call FrameView::hide() for the main frame but it does not have a FrameView
  yet (because the load has not started). We start the load and end up creating
  a FrameView. The FrameView constructor was calling FrameView::show()
  unconditionally, thus making the FrameView think is visible, even though its
  page isn't. At this point, FrameView::isOffscreen() was returning false
  and animations would keep running, even though the page is not visible.

To address the issue, we now call FrameView::show() in FrameView::create() only
if the Page is actually visible, instead of calling it unconditionally. If the
page ever becomes visible, Page::setIsVisibleInternal(true) will be called and
it will take care of calling FrameView::show() then.

Tests: svg/animations/animations-paused-in-background-page-iframe.html
       svg/animations/animations-paused-in-background-page.html

* page/FrameView.cpp:
(WebCore::FrameView::create):

LayoutTests:

Extend layout test coverage.

* svg/animations/animations-paused-in-background-page-expected.txt: Added.
* svg/animations/animations-paused-in-background-page-iframe-expected.txt: Added.
* svg/animations/animations-paused-in-background-page-iframe.html: Added.
* svg/animations/animations-paused-in-background-page.html: Added.
* svg/animations/resources/iframe-with-animated-svg-image.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (214560 => 214561)


--- trunk/LayoutTests/ChangeLog	2017-03-29 20:38:54 UTC (rev 214560)
+++ trunk/LayoutTests/ChangeLog	2017-03-29 20:54:21 UTC (rev 214561)
@@ -1,3 +1,19 @@
+2017-03-29  Chris Dumez  <cdu...@apple.com>
+
+        Animated SVG images are not paused in pages loaded in the background
+        https://bugs.webkit.org/show_bug.cgi?id=170043
+        <rdar://problem/31234412>
+
+        Reviewed by Simon Fraser.
+
+        Extend layout test coverage.
+
+        * svg/animations/animations-paused-in-background-page-expected.txt: Added.
+        * svg/animations/animations-paused-in-background-page-iframe-expected.txt: Added.
+        * svg/animations/animations-paused-in-background-page-iframe.html: Added.
+        * svg/animations/animations-paused-in-background-page.html: Added.
+        * svg/animations/resources/iframe-with-animated-svg-image.html: Added.
+
 2017-03-29  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Post-commit test gardening after r214546

Modified: trunk/LayoutTests/platform/ios/TestExpectations (214560 => 214561)


--- trunk/LayoutTests/platform/ios/TestExpectations	2017-03-29 20:38:54 UTC (rev 214560)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2017-03-29 20:54:21 UTC (rev 214561)
@@ -309,6 +309,8 @@
 webkit.org/b/165799 fast/events/page-visibility-onvisibilitychange.html [ Skip ]
 webkit.org/b/165799 media/media-playback-page-visibility.html [ Skip ]
 webkit.org/b/165799 svg/animations/animations-paused-page-non-visible.html [ Skip ]
+webkit.org/b/165799 svg/animations/animations-paused-in-background-page-iframe.html [ Skip ]
+webkit.org/b/165799 svg/animations/animations-paused-in-background-page.html [ Skip ]
 
 # AutoFill button is not supported
 fast/forms/auto-fill-button/mouse-down-input-mouse-release-auto-fill-button.html

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (214560 => 214561)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2017-03-29 20:38:54 UTC (rev 214560)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2017-03-29 20:54:21 UTC (rev 214561)
@@ -125,6 +125,8 @@
 fast/images/animated-gif-zooming.html [ Skip ]
 svg/animations/animated-svg-image-outside-viewport-paused.html [ Skip ]
 svg/animations/animated-svg-image-removed-from-document-paused.html [ Skip ]
+svg/animations/animations-paused-in-background-page-iframe.html [ Skip ]
+svg/animations/animations-paused-in-background-page.html [ Skip ]
 
 # WK1 uses the native scrollview for scrolling by page.
 scrollbars/scrolling-backward-by-page-accounting-bottom-fixed-elements-on-keyboard-spacebar.html

Added: trunk/LayoutTests/svg/animations/animations-paused-in-background-page-expected.txt (0 => 214561)


--- trunk/LayoutTests/svg/animations/animations-paused-in-background-page-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/animations-paused-in-background-page-expected.txt	2017-03-29 20:54:21 UTC (rev 214561)
@@ -0,0 +1,14 @@
+Tests that animated SVG images are properly paused when the page is no longer visible
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.isImageAnimating(testImage) is true
+Setting page visibility to hidden
+PASS internals.isImageAnimating(testImage) became false
+Setting page visibility to visible
+PASS internals.isImageAnimating(testImage) became false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/svg/animations/animations-paused-in-background-page-iframe-expected.txt (0 => 214561)


--- trunk/LayoutTests/svg/animations/animations-paused-in-background-page-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/animations-paused-in-background-page-iframe-expected.txt	2017-03-29 20:54:21 UTC (rev 214561)
@@ -0,0 +1,14 @@
+Tests that animated SVG images are properly paused when loaded in a new iframe inside a hidden page
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Setting page visibility to hidden
+PASS document.hidden is true
+PASS internals.isImageAnimating(testImage) is false
+Setting page visibility to visible
+PASS internals.isImageAnimating(testImage) became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/svg/animations/animations-paused-in-background-page-iframe.html (0 => 214561)


--- trunk/LayoutTests/svg/animations/animations-paused-in-background-page-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/animations-paused-in-background-page-iframe.html	2017-03-29 20:54:21 UTC (rev 214561)
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that animated SVG images are properly paused when loaded in a new iframe inside a hidden page");
+jsTestIsAsync = true;
+
+function frameLoadedInBackground()
+{
+    setTimeout(function() {
+        testImage = frame.contentDocument.getElementById("testImage");
+        shouldBeFalse("internals.isImageAnimating(testImage)");
+
+        document._onvisibilitychange_ = null;
+        debug("Setting page visibility to visible");
+        if (window.testRunner)
+            testRunner.setPageVisibility('visible');
+
+        shouldBecomeEqual("internals.isImageAnimating(testImage)", "true", finishJSTest);
+    }, 30);
+}
+
+window._onload_ = function() {
+    document._onvisibilitychange_ = function() {
+        setTimeout(function() {
+            shouldBeTrue("document.hidden");
+            frame = document.createElement("iframe");
+            frame.src = ""
+            frame._onload_ = frameLoadedInBackground;
+            document.body.appendChild(frame);
+        }, 30);
+    };
+
+    debug("Setting page visibility to hidden");
+    if (window.testRunner)
+        testRunner.setPageVisibility('hidden');
+}
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/svg/animations/animations-paused-in-background-page.html (0 => 214561)


--- trunk/LayoutTests/svg/animations/animations-paused-in-background-page.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/animations-paused-in-background-page.html	2017-03-29 20:54:21 UTC (rev 214561)
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that animated SVG images are properly paused when the page is no longer visible");
+jsTestIsAsync = true;
+
+function makePageVisible()
+{
+    debug("Setting page visibility to visible");
+    if (window.testRunner)
+        testRunner.setPageVisibility('visible');
+    shouldBecomeEqual("internals.isImageAnimating(testImage)", "false", finishJSTest);
+}
+
+window._onload_ = function() {
+    testImage = document.getElementById("testImage");
+    shouldBeTrue("internals.isImageAnimating(testImage)");
+
+    debug("Setting page visibility to hidden");
+    if (window.testRunner)
+        testRunner.setPageVisibility('hidden');
+
+    shouldBecomeEqual("internals.isImageAnimating(testImage)", "false", makePageVisible);
+}
+</script>
+<img id="testImage" src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/svg/animations/resources/iframe-with-animated-svg-image.html (0 => 214561)


--- trunk/LayoutTests/svg/animations/resources/iframe-with-animated-svg-image.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/resources/iframe-with-animated-svg-image.html	2017-03-29 20:54:21 UTC (rev 214561)
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<img id="testImage" src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (214560 => 214561)


--- trunk/Source/WebCore/ChangeLog	2017-03-29 20:38:54 UTC (rev 214560)
+++ trunk/Source/WebCore/ChangeLog	2017-03-29 20:54:21 UTC (rev 214561)
@@ -1,3 +1,49 @@
+2017-03-29  Chris Dumez  <cdu...@apple.com>
+
+        Animated SVG images are not paused in pages loaded in the background
+        https://bugs.webkit.org/show_bug.cgi?id=170043
+        <rdar://problem/31234412>
+
+        Reviewed by Simon Fraser.
+
+        Animated SVG images are not paused in pages loaded in the background. We rely
+        on FrameView::isOffscreen() to stop images animations in background tab (See
+        logic in RenderElement's shouldRepaintForImageAnimation()). This works fine
+        if a tab is visble and then becomes hidden (i.e. by switching to another
+        tab). However, in the case where the tab gets loaded while in the background
+        (e.g. opening link in new background tab, or session restore), then the
+        animations would not be paused, due to FrameView::isOffscreen() erroneously
+        returning false in this case.
+
+        Normally, the following chain of events happens:
+        - Page is visible, we construct a main frame and its FrameView for loading
+          the page. When a FrameView is constructed, we call FrameView::show() to
+          make it visible. Then, if the page becomes non-visible, we call
+          Page::setIsVisibleInternal(false) which calls FrameView::hide(). After
+          that, FrameView::isOffscreen() correctly returns true because we properly
+          called FrameView::hide().
+
+        However, when doing a load while the Page is hidden, the following was
+        happening:
+        - Page is not visible, we call Page::setIsVisibleInternal(false) which tries
+          to call FrameView::hide() for the main frame but it does not have a FrameView
+          yet (because the load has not started). We start the load and end up creating
+          a FrameView. The FrameView constructor was calling FrameView::show()
+          unconditionally, thus making the FrameView think is visible, even though its
+          page isn't. At this point, FrameView::isOffscreen() was returning false
+          and animations would keep running, even though the page is not visible.
+
+        To address the issue, we now call FrameView::show() in FrameView::create() only
+        if the Page is actually visible, instead of calling it unconditionally. If the
+        page ever becomes visible, Page::setIsVisibleInternal(true) will be called and
+        it will take care of calling FrameView::show() then.
+
+        Tests: svg/animations/animations-paused-in-background-page-iframe.html
+               svg/animations/animations-paused-in-background-page.html
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::create):
+
 2017-03-29  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Links with empty hrefs should not be drag sources

Modified: trunk/Source/WebCore/page/FrameView.cpp (214560 => 214561)


--- trunk/Source/WebCore/page/FrameView.cpp	2017-03-29 20:38:54 UTC (rev 214560)
+++ trunk/Source/WebCore/page/FrameView.cpp	2017-03-29 20:54:21 UTC (rev 214561)
@@ -296,7 +296,8 @@
 Ref<FrameView> FrameView::create(Frame& frame)
 {
     Ref<FrameView> view = adoptRef(*new FrameView(frame));
-    view->show();
+    if (frame.page() && frame.page()->isVisible())
+        view->show();
     return view;
 }
 
@@ -304,7 +305,8 @@
 {
     Ref<FrameView> view = adoptRef(*new FrameView(frame));
     view->Widget::setFrameRect(IntRect(view->location(), initialSize));
-    view->show();
+    if (frame.page() && frame.page()->isVisible())
+        view->show();
     return view;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to