Index: third_party/WebKit/Source/core/dom/Fullscreen.cpp |
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp |
index ff1331bd4cadc423dc311e1626746ce7ce733867..5ff6e9afb1a7efe9d35c610f605a5c28ce74a39b 100644 |
--- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp |
+++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp |
@@ -33,7 +33,6 @@ |
#include "core/dom/ElementTraversal.h" |
#include "core/dom/StyleEngine.h" |
#include "core/events/Event.h" |
-#include "core/frame/FrameHost.h" |
#include "core/frame/HostsUsingFeatures.h" |
#include "core/frame/LocalFrame.h" |
#include "core/frame/Settings.h" |
@@ -298,8 +297,8 @@ void Fullscreen::requestFullscreen(Element& element, |
} |
} |
- // Ignore this request if the document is not in a live frame. |
- if (!document.isActive()) |
+ // Ignore this call if the document is not in a live frame. |
+ if (!document.isActive() || !document.frame()) |
return; |
// If |element| is on top of |doc|'s fullscreen element stack, terminate these |
@@ -399,7 +398,8 @@ void Fullscreen::requestFullscreen(Element& element, |
// 5. Return, and run the remaining steps asynchronously. |
// 6. Optionally, perform some animation. |
- document.frameHost()->chromeClient().enterFullscreenForElement(&element); |
+ from(document).m_pendingFullscreenElement = &element; |
+ document.frame()->chromeClient().enterFullscreen(*document.frame()); |
// 7. Optionally, display a message indicating how the user can exit |
// displaying the context object fullscreen. |
@@ -441,10 +441,11 @@ void Fullscreen::fullyExitFullscreen(Document& document) { |
void Fullscreen::exitFullscreen(Document& document) { |
// The exitFullscreen() method must run these steps: |
- // 1. Let doc be the context object. (i.e. "this") |
- if (!document.isActive()) |
+ // Ignore this call if the document is not in a live frame. |
+ if (!document.isActive() || !document.frame()) |
return; |
+ // 1. Let doc be the context object. (i.e. "this") |
// 2. If doc's fullscreen element stack is empty, terminate these steps. |
if (!fullscreenElementFrom(document)) |
return; |
@@ -454,9 +455,8 @@ void Fullscreen::exitFullscreen(Document& document) { |
// child of the doc is last and the document furthest away from the doc is |
// first. |
HeapDeque<Member<Document>> descendants; |
- for (Frame* descendant = |
- document.frame() ? document.frame()->tree().traverseNext() : nullptr; |
- descendant; descendant = descendant->tree().traverseNext()) { |
+ for (Frame* descendant = document.frame()->tree().traverseNext(); descendant; |
+ descendant = descendant->tree().traverseNext()) { |
if (!descendant->isLocalFrame()) |
continue; |
DCHECK(toLocalFrame(descendant)->document()); |
@@ -521,23 +521,15 @@ void Fullscreen::exitFullscreen(Document& document) { |
// 6. Return, and run the remaining steps asynchronously. |
// 7. Optionally, perform some animation. |
- FrameHost* host = document.frameHost(); |
- |
- // Speculative fix for engaget.com/videos per crbug.com/336239. |
- // FIXME: This check is wrong. We DCHECK(document->isActive()) above |
- // so this should be redundant and should be removed! |
- if (!host) |
- return; |
- |
- // Only exit out of full screen window mode if there are no remaining elements |
- // in the full screen stack. |
+ // Only exit fullscreen mode if the fullscreen element stack is empty. |
if (!newTop) { |
- host->chromeClient().exitFullscreen(document.frame()); |
+ document.frame()->chromeClient().exitFullscreen(*document.frame()); |
return; |
} |
- // Otherwise, notify the chrome of the new full screen element. |
- host->chromeClient().enterFullscreenForElement(newTop); |
+ // Otherwise, enter fullscreen for the fullscreen element stack's top element. |
+ from(document).m_pendingFullscreenElement = newTop; |
+ from(document).didEnterFullscreen(); |
} |
// https://fullscreen.spec.whatwg.org/#dom-document-fullscreenenabled |
@@ -549,14 +541,33 @@ bool Fullscreen::fullscreenEnabled(Document& document) { |
fullscreenIsSupported(document); |
} |
-void Fullscreen::didEnterFullscreenForElement(Element* element) { |
- DCHECK(element); |
+void Fullscreen::didEnterFullscreen() { |
if (!document()->isActive() || !document()->frame()) |
return; |
+ // Start the timer for events enqueued by |requestFullscreen()|. The hover |
+ // state update is scheduled first so that it's done when the events fire. |
+ document()->frame()->eventHandler().scheduleHoverStateUpdate(); |
+ m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE); |
+ |
+ Element* element = m_pendingFullscreenElement.release(); |
+ if (!element) |
+ return; |
+ |
if (m_currentFullScreenElement == element) |
return; |
+ if (!element->isConnected() || &element->document() != document()) { |
+ // The element was removed or has moved to another document since the |
+ // |requestFullscreen()| call. Exit fullscreen again to recover. |
+ // TODO(foolip): Fire a fullscreenerror event. This is currently difficult |
+ // because the fullscreenchange event has already been enqueued and possibly |
+ // even fired. https://crbug.com/402376 |
+ LocalFrame& frame = *document()->frame(); |
+ frame.chromeClient().exitFullscreen(frame); |
+ return; |
+ } |
+ |
if (m_fullScreenLayoutObject) |
m_fullScreenLayoutObject->unwrapLayoutObject(); |
@@ -604,10 +615,6 @@ void Fullscreen::didEnterFullscreenForElement(Element* element) { |
// FIXME: This should not call updateStyleAndLayoutTree. |
document()->updateStyleAndLayoutTree(); |
- document()->frame()->eventHandler().scheduleHoverStateUpdate(); |
- |
- m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE); |
- |
document()->frame()->chromeClient().fullscreenElementChanged(previousElement, |
element); |
} |
@@ -616,6 +623,18 @@ void Fullscreen::didExitFullscreen() { |
if (!document()->isActive() || !document()->frame()) |
return; |
+ // Start the timer for events enqueued by |exitFullscreen()|. The hover state |
+ // update is scheduled first so that it's done when the events fire. |
+ document()->frame()->eventHandler().scheduleHoverStateUpdate(); |
+ m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE); |
+ |
+ // If fullscreen was canceled by the browser, e.g. if the user pressed Esc, |
+ // then |exitFullscreen()| was never called. Let |fullyExitFullscreen()| clear |
+ // the fullscreen element stack and fire any events as necessary. |
+ // TODO(foolip): Remove this when state changes and events are synchronized |
+ // with animation frames. https://crbug.com/402376 |
+ fullyExitFullscreen(*document()); |
+ |
if (!m_currentFullScreenElement) |
return; |
@@ -633,17 +652,6 @@ void Fullscreen::didExitFullscreen() { |
Element* previousElement = m_currentFullScreenElement; |
m_currentFullScreenElement = nullptr; |
- document()->frame()->eventHandler().scheduleHoverStateUpdate(); |
- |
- // When fullyExitFullscreen is called, we call exitFullscreen on the |
- // topDocument(). That means that the events will be queued there. So if we |
- // have no events here, start the timer on the exiting document. |
- Document* exitingDocument = document(); |
- if (m_eventQueue.isEmpty()) |
- exitingDocument = &topmostLocalAncestor(*document()); |
- DCHECK(exitingDocument); |
- from(*exitingDocument).m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE); |
- |
m_forCrossProcessDescendant = false; |
document()->frame()->chromeClient().fullscreenElementChanged(previousElement, |
@@ -692,8 +700,7 @@ void Fullscreen::enqueueChangeEvent(Document& document, |
event = createEvent(EventTypeNames::webkitfullscreenchange, *target); |
} |
m_eventQueue.append(event); |
- // NOTE: The timer is started in |
- // didEnterFullscreenForElement/didExitFullscreen. |
+ // NOTE: The timer is started in didEnterFullscreen/didExitFullscreen. |
} |
void Fullscreen::enqueueErrorEvent(Element& element, RequestType requestType) { |
@@ -766,8 +773,9 @@ void Fullscreen::pushFullscreenElementStack(Element& element, |
} |
DEFINE_TRACE(Fullscreen) { |
- visitor->trace(m_currentFullScreenElement); |
+ visitor->trace(m_pendingFullscreenElement); |
visitor->trace(m_fullscreenElementStack); |
+ visitor->trace(m_currentFullScreenElement); |
visitor->trace(m_eventQueue); |
Supplement<Document>::trace(visitor); |
ContextLifecycleObserver::trace(visitor); |