[iOS] Suspend and resume device motion and device orientation updates when page is...
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Dec 2015 02:53:12 +0000 (02:53 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Dec 2015 02:53:12 +0000 (02:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151840
<rdar://problem/23753931>

Reviewed by Simon Fraser.

.:

Add a manual test that can be used to verify that we suspend dispatching device motion and
device orientation events when the page is hidden.

* ManualTests/ios/resources/suspend-orientation-and-motion-events-when-page-becomes-hidden.js: Added.
(resetTest):
(checkEvent):
(handleVisibilityChange):
* ManualTests/ios/suspend-orientation-and-motion-events-when-page-becomes-hidden.html: Added.

Source/WebCore:

* dom/Document.cpp:
(WebCore::Document::suspendDeviceMotionAndOrientationUpdates): Added.
(WebCore::Document::resumeDeviceMotionAndOrientationUpdates): Added.
(WebCore::Document::platformSuspendOrStopActiveDOMObjects): Moved logic to suspend device motion and
orientation updates from here to Document::suspendDeviceMotionAndOrientationUpdates().
(WebCore::Document::suspendActiveDOMObjects): Modified to call Document::suspendDeviceMotionAndOrientationUpdates().
(WebCore::Document::resumeActiveDOMObjects): Modified to call Document::resumeDeviceMotionAndOrientationUpdates().
* dom/Document.h:
* page/Page.cpp:
(WebCore::Page::setIsVisibleInternal): Suspend device motion and orientation updates when the page is hidden and
resume updates when the page is visible.
(WebCore::Page::suspendDeviceMotionAndOrientationUpdates): Added.
(WebCore::Page::resumeDeviceMotionAndOrientationUpdates): Added.
* page/Page.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@193885 268f45cc-cd09-0410-ab3c-d52691b4dbfc

ChangeLog
ManualTests/ios/resources/suspend-orientation-and-motion-events-when-page-becomes-hidden.js [new file with mode: 0644]
ManualTests/ios/suspend-orientation-and-motion-events-when-page-becomes-hidden.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h

index 942a771..7cbecc1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2015-12-09  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Suspend and resume device motion and device orientation updates when page is hidden and visible, respectively
+        https://bugs.webkit.org/show_bug.cgi?id=151840
+        <rdar://problem/23753931>
+
+        Reviewed by Simon Fraser.
+
+        Add a manual test that can be used to verify that we suspend dispatching device motion and
+        device orientation events when the page is hidden.
+
+        * ManualTests/ios/resources/suspend-orientation-and-motion-events-when-page-becomes-hidden.js: Added.
+        (resetTest):
+        (checkEvent):
+        (handleVisibilityChange):
+        * ManualTests/ios/suspend-orientation-and-motion-events-when-page-becomes-hidden.html: Added.
+
 2015-12-07  Alex Christensen  <achristensen@webkit.org>
 
         Fix internal Windows build
diff --git a/ManualTests/ios/resources/suspend-orientation-and-motion-events-when-page-becomes-hidden.js b/ManualTests/ios/resources/suspend-orientation-and-motion-events-when-page-becomes-hidden.js
new file mode 100644 (file)
index 0000000..106e9ce
--- /dev/null
@@ -0,0 +1,41 @@
+var eventFrequencyTable;
+
+function resetTest()
+{
+    eventFrequencyTable = {};
+}
+
+function log(message)
+{
+    document.getElementById("console").appendChild(document.createTextNode(message + "\n"));
+}
+
+function checkEvent(event)
+{
+    if (document.visibilityState === "visible")
+        return;
+    var type = event.type;
+    if (!eventFrequencyTable[type])
+        eventFrequencyTable[type] = 0;
+    ++eventFrequencyTable[type];
+}
+
+function handleVisibilityChange()
+{
+    if (document.visibilityState === "hidden")
+        return;
+    var receivedEventsMessageParts = [];
+    for (var type in eventFrequencyTable)
+        receivedEventsMessageParts.push(type + " (\u00D7 " + eventFrequencyTable[type] + ")");
+    if (receivedEventsMessageParts.length)
+        log("Expected to receive no events when the page was hidden, but received: " + receivedEventsMessageParts.join(", ") + ".");
+    else
+        log("Received no events when the page was hidden.");
+    resetTest();
+}
+
+resetTest();
+
+window.addEventListener("devicemotion", checkEvent, false);
+window.addEventListener("deviceorientation", checkEvent, false);
+document.addEventListener("visibilitychange", handleVisibilityChange, false);
diff --git a/ManualTests/ios/suspend-orientation-and-motion-events-when-page-becomes-hidden.html b/ManualTests/ios/suspend-orientation-and-motion-events-when-page-becomes-hidden.html
new file mode 100644 (file)
index 0000000..f99aa16
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="resources/suspend-orientation-and-motion-events-when-page-becomes-hidden.js"></script>
+</head>
+<body>
+<p>This test can be used to verify that <code>devicemotion</code> and <code>deviceorientation</code> events are not dispatched when the page is hidden.</p>
+<button onclick="window.open('suspend-orientation-and-motion-events-when-page-becomes-hidden.html')">Open this page in a child window to verify that this page does not receive events when the child window is the front-most window</button>
+<pre id="console"></pre>
+</body>
+</html>
index 1f6e380..8485dd9 100644 (file)
@@ -1,5 +1,28 @@
 2015-12-09  Daniel Bates  <dabates@apple.com>
 
+        [iOS] Suspend and resume device motion and device orientation updates when page is hidden and visible, respectively
+        https://bugs.webkit.org/show_bug.cgi?id=151840
+        <rdar://problem/23753931>
+
+        Reviewed by Simon Fraser.
+
+        * dom/Document.cpp:
+        (WebCore::Document::suspendDeviceMotionAndOrientationUpdates): Added.
+        (WebCore::Document::resumeDeviceMotionAndOrientationUpdates): Added.
+        (WebCore::Document::platformSuspendOrStopActiveDOMObjects): Moved logic to suspend device motion and
+        orientation updates from here to Document::suspendDeviceMotionAndOrientationUpdates().
+        (WebCore::Document::suspendActiveDOMObjects): Modified to call Document::suspendDeviceMotionAndOrientationUpdates().
+        (WebCore::Document::resumeActiveDOMObjects): Modified to call Document::resumeDeviceMotionAndOrientationUpdates().
+        * dom/Document.h:
+        * page/Page.cpp:
+        (WebCore::Page::setIsVisibleInternal): Suspend device motion and orientation updates when the page is hidden and
+        resume updates when the page is visible.
+        (WebCore::Page::suspendDeviceMotionAndOrientationUpdates): Added.
+        (WebCore::Page::resumeDeviceMotionAndOrientationUpdates): Added.
+        * page/Page.h:
+
+2015-12-09  Daniel Bates  <dabates@apple.com>
+
         Unify iOS Frame::setTimersPaused() logic and Frame::{suspend, resume}ActiveDOMObjectsAndAnimations()
         https://bugs.webkit.org/show_bug.cgi?id=152006
 
index 2ee54f7..006d1dc 100644 (file)
@@ -2345,16 +2345,35 @@ void Document::removeAllEventListeners()
         node->removeAllEventListeners();
 }
 
-void Document::platformSuspendOrStopActiveDOMObjects()
+void Document::suspendDeviceMotionAndOrientationUpdates()
 {
-#if PLATFORM(IOS)
-#if ENABLE(DEVICE_ORIENTATION)
+    if (m_areDeviceMotionAndOrientationUpdatesSuspended)
+        return;
+    m_areDeviceMotionAndOrientationUpdatesSuspended = true;
+#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS)
     if (m_deviceMotionController)
         m_deviceMotionController->suspendUpdates();
     if (m_deviceOrientationController)
         m_deviceOrientationController->suspendUpdates();
 #endif
+}
+
+void Document::resumeDeviceMotionAndOrientationUpdates()
+{
+    if (!m_areDeviceMotionAndOrientationUpdatesSuspended)
+        return;
+    m_areDeviceMotionAndOrientationUpdatesSuspended = false;
+#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS)
+    if (m_deviceMotionController)
+        m_deviceMotionController->resumeUpdates();
+    if (m_deviceOrientationController)
+        m_deviceOrientationController->resumeUpdates();
+#endif
+}
 
+void Document::platformSuspendOrStopActiveDOMObjects()
+{
+#if PLATFORM(IOS)
     if (WebThreadCountOfObservedContentModifiers() > 0) {
         Frame* frame = this->frame();
         if (Page* page = frame ? frame->page() : nullptr)
@@ -2366,19 +2385,14 @@ void Document::platformSuspendOrStopActiveDOMObjects()
 void Document::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
 {
     ScriptExecutionContext::suspendActiveDOMObjects(why);
+    suspendDeviceMotionAndOrientationUpdates();
     platformSuspendOrStopActiveDOMObjects();
 }
 
 void Document::resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
 {
     ScriptExecutionContext::resumeActiveDOMObjects(why);
-
-#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS)
-    if (m_deviceMotionController)
-        m_deviceMotionController->resumeUpdates();
-    if (m_deviceOrientationController)
-        m_deviceOrientationController->resumeUpdates();
-#endif
+    resumeDeviceMotionAndOrientationUpdates();
     // FIXME: For iOS, do we need to add content change observers that were removed in Document::suspendActiveDOMObjects()?
 }
 
index 4c202a2..319dc44 100644 (file)
@@ -604,6 +604,9 @@ public:
     virtual void resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension) override final;
     virtual void stopActiveDOMObjects() override final;
 
+    void suspendDeviceMotionAndOrientationUpdates();
+    void resumeDeviceMotionAndOrientationUpdates();
+
     RenderView* renderView() const { return m_renderView.get(); }
 
     bool renderTreeBeingDestroyed() const { return m_renderTreeBeingDestroyed; }
@@ -1775,6 +1778,7 @@ private:
 #if ENABLE(MEDIA_SESSION)
     RefPtr<MediaSession> m_defaultMediaSession;
 #endif
+    bool m_areDeviceMotionAndOrientationUpdatesSuspended { false };
 };
 
 inline void Document::notifyRemovePendingSheetIfNeeded()
index 30e585d..b748112 100644 (file)
@@ -1312,6 +1312,9 @@ void Page::setIsVisibleInternal(bool isVisible)
         m_isPrerender = false;
 
         resumeScriptedAnimations();
+#if PLATFORM(IOS)
+        resumeDeviceMotionAndOrientationUpdates();
+#endif
 
         if (FrameView* view = mainFrame().view())
             view->show();
@@ -1333,6 +1336,9 @@ void Page::setIsVisibleInternal(bool isVisible)
         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
             mainFrame().animation().suspendAnimations();
 
+#if PLATFORM(IOS)
+        suspendDeviceMotionAndOrientationUpdates();
+#endif
         suspendScriptedAnimations();
 
         if (FrameView* view = mainFrame().view())
@@ -1556,6 +1562,22 @@ void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& ob
     m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect));
 }
 
+void Page::suspendDeviceMotionAndOrientationUpdates()
+{
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (Document* document = frame->document())
+            document->suspendDeviceMotionAndOrientationUpdates();
+    }
+}
+
+void Page::resumeDeviceMotionAndOrientationUpdates()
+{
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (Document* document = frame->document())
+            document->resumeDeviceMotionAndOrientationUpdates();
+    }
+}
+
 void Page::suspendActiveDOMObjectsAndAnimations()
 {
     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
index 9ee50c7..cb249f9 100644 (file)
@@ -394,6 +394,9 @@ public:
 
     WEBCORE_EXPORT void suspendActiveDOMObjectsAndAnimations();
     WEBCORE_EXPORT void resumeActiveDOMObjectsAndAnimations();
+    void suspendDeviceMotionAndOrientationUpdates();
+    void resumeDeviceMotionAndOrientationUpdates();
+
 #ifndef NDEBUG
     void setIsPainting(bool painting) { m_isPainting = painting; }
     bool isPainting() const { return m_isPainting; }