| 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); | 
|  |