Chromium Code Reviews| 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..366a08e3a2b7ffdf288d07bc3d998281e2ffa3f9 100644 | 
| --- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp | 
| +++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp | 
| @@ -31,6 +31,7 @@ | 
| #include "core/dom/Document.h" | 
| #include "core/dom/ElementTraversal.h" | 
| +#include "core/dom/FullscreenCallbacks.h" | 
| #include "core/dom/StyleEngine.h" | 
| #include "core/events/Event.h" | 
| #include "core/frame/FrameHost.h" | 
| @@ -280,6 +281,33 @@ void Fullscreen::contextDestroyed() { | 
| m_fullscreenElementStack.clear(); | 
| } | 
| +// RequestFullscreenCallbacks hold the data for a pending request. | 
| +// FullscreenController invokes the success or error callback. | 
| +class RequestFullscreenCallbacks final : public FullscreenCallbacks { | 
| + USING_FAST_MALLOC(RequestFullscreenCallbacks); | 
| + WTF_MAKE_NONCOPYABLE(RequestFullscreenCallbacks); | 
| + | 
| + public: | 
| + static std::unique_ptr<FullscreenCallbacks> | 
| + create(Document& document, Element& element, Fullscreen::RequestType type) { | 
| + return wrapUnique(new RequestFullscreenCallbacks(Fullscreen::from(document), | 
| 
 
esprehn
2016/12/01 20:26:12
The element and the document can disagree, is ther
 
foolip
2016/12/01 23:05:01
I was working on this today, just uploaded "handle
 
 | 
| + element, type)); | 
| + } | 
| + void onSuccess() override { m_fullscreen->didEnterFullscreen(*m_element); } | 
| + void onError() override { | 
| + m_fullscreen->enqueueErrorEvent(*m_element, m_type); | 
| + } | 
| + | 
| + private: | 
| + RequestFullscreenCallbacks(Fullscreen& fullscreen, | 
| + Element& element, | 
| + Fullscreen::RequestType type) | 
| + : m_fullscreen(fullscreen), m_element(element), m_type(type) {} | 
| + Persistent<Fullscreen> m_fullscreen; | 
| + Persistent<Element> m_element; | 
| + Fullscreen::RequestType m_type; | 
| +}; | 
| + | 
| // https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen | 
| void Fullscreen::requestFullscreen(Element& element, | 
| RequestType requestType, | 
| @@ -298,8 +326,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 +427,9 @@ void Fullscreen::requestFullscreen(Element& element, | 
| // 5. Return, and run the remaining steps asynchronously. | 
| // 6. Optionally, perform some animation. | 
| - document.frameHost()->chromeClient().enterFullscreenForElement(&element); | 
| + document.frameHost()->chromeClient().enterFullscreen( | 
| + *document.frame(), | 
| + RequestFullscreenCallbacks::create(document, element, requestType)); | 
| // 7. Optionally, display a message indicating how the user can exit | 
| // displaying the context object fullscreen. | 
| @@ -441,10 +471,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 +485,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()); | 
| @@ -529,15 +559,14 @@ void Fullscreen::exitFullscreen(Document& document) { | 
| 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()); | 
| + host->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).didEnterFullscreen(*newTop); | 
| } | 
| // https://fullscreen.spec.whatwg.org/#dom-document-fullscreenenabled | 
| @@ -549,19 +578,18 @@ bool Fullscreen::fullscreenEnabled(Document& document) { | 
| fullscreenIsSupported(document); | 
| } | 
| -void Fullscreen::didEnterFullscreenForElement(Element* element) { | 
| - DCHECK(element); | 
| +void Fullscreen::didEnterFullscreen(Element& element) { | 
| if (!document()->isActive() || !document()->frame()) | 
| return; | 
| - if (m_currentFullScreenElement == element) | 
| + if (m_currentFullScreenElement == &element) | 
| return; | 
| if (m_fullScreenLayoutObject) | 
| m_fullScreenLayoutObject->unwrapLayoutObject(); | 
| Element* previousElement = m_currentFullScreenElement; | 
| - m_currentFullScreenElement = element; | 
| + m_currentFullScreenElement = &element; | 
| // Create a placeholder block for a the full-screen element, to keep the page | 
| // from reflowing when the element is removed from the normal flow. Only do | 
| @@ -609,7 +637,7 @@ void Fullscreen::didEnterFullscreenForElement(Element* element) { | 
| m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE); | 
| document()->frame()->chromeClient().fullscreenElementChanged(previousElement, | 
| - element); | 
| + &element); | 
| } | 
| void Fullscreen::didExitFullscreen() { | 
| @@ -619,6 +647,13 @@ void Fullscreen::didExitFullscreen() { | 
| if (!m_currentFullScreenElement) | 
| return; | 
| + // 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_forCrossProcessDescendant) | 
| m_currentFullScreenElement->setContainsFullScreenElement(false); | 
| @@ -692,8 +727,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) { |