Index: third_party/WebKit/Source/web/FullscreenController.cpp |
diff --git a/third_party/WebKit/Source/web/FullscreenController.cpp b/third_party/WebKit/Source/web/FullscreenController.cpp |
index 09e664a31adbfe5bcc0c31aec95d99c9fb382704..bf58338516683b035902a86af4b4da813402b5ff 100644 |
--- a/third_party/WebKit/Source/web/FullscreenController.cpp |
+++ b/third_party/WebKit/Source/web/FullscreenController.cpp |
@@ -32,99 +32,120 @@ |
#include "core/dom/Document.h" |
#include "core/dom/Fullscreen.h" |
+#include "core/dom/FullscreenCallbacks.h" |
#include "core/frame/FrameView.h" |
#include "core/frame/LocalFrame.h" |
#include "core/frame/PageScaleConstraintsSet.h" |
#include "core/html/HTMLVideoElement.h" |
#include "core/layout/LayoutFullScreen.h" |
-#include "platform/RuntimeEnabledFeatures.h" |
#include "public/platform/WebLayerTreeView.h" |
#include "public/web/WebFrameClient.h" |
#include "web/WebLocalFrameImpl.h" |
-#include "web/WebSettingsImpl.h" |
#include "web/WebViewImpl.h" |
namespace blink { |
-FullscreenController* FullscreenController::create(WebViewImpl* webViewImpl) { |
- return new FullscreenController(webViewImpl); |
+std::unique_ptr<FullscreenController> FullscreenController::create( |
+ WebViewImpl* webViewImpl) { |
+ return wrapUnique(new FullscreenController(webViewImpl)); |
} |
FullscreenController::FullscreenController(WebViewImpl* webViewImpl) |
- : m_webViewImpl(webViewImpl), |
- m_haveEnteredFullscreen(false), |
- m_exitFullscreenPageScaleFactor(0), |
- m_needsScrollAndScaleRestore(false), |
- m_isCancelingFullscreen(false) {} |
+ : m_webViewImpl(webViewImpl) {} |
void FullscreenController::didEnterFullscreen() { |
- if (!m_provisionalFullscreenElement) |
+ // Browser::EnterFullscreenModeForTab can enter fullscreen without going |
+ // through Fullscreen::requestFullscreen, in which case there will be no |
+ // fullscreen element. Do nothing. |
+ if (m_state != State::kEnteringFullscreen) |
return; |
- Element* element = m_provisionalFullscreenElement.release(); |
- Document& document = element->document(); |
- m_fullscreenFrame = document.frame(); |
- |
- if (!m_fullscreenFrame) |
- return; |
+ updatePageScaleConstraints(false); |
+ m_webViewImpl->setPageScaleFactor(1.0f); |
+ if (m_webViewImpl->mainFrame()->isWebLocalFrame()) |
+ m_webViewImpl->mainFrame()->setScrollOffset(WebSize()); |
+ m_webViewImpl->setVisualViewportOffset(FloatPoint()); |
- if (!m_haveEnteredFullscreen) { |
- updatePageScaleConstraints(false); |
- m_webViewImpl->setPageScaleFactor(1.0f); |
- if (m_webViewImpl->mainFrame()->isWebLocalFrame()) |
- m_webViewImpl->mainFrame()->setScrollOffset(WebSize()); |
- m_webViewImpl->setVisualViewportOffset(FloatPoint()); |
- m_haveEnteredFullscreen = true; |
- } |
+ DCHECK(!m_callbacksList.isEmpty()); |
+ CallbacksList callbacksList; |
+ callbacksList.swap(m_callbacksList); |
+ for (auto& callbacks : callbacksList) |
+ callbacks->onSuccess(); |
- Fullscreen::from(document).didEnterFullscreenForElement(element); |
- DCHECK_EQ(Fullscreen::currentFullScreenElementFrom(document), element); |
+ m_state = State::kFullscreen; |
} |
void FullscreenController::didExitFullscreen() { |
- if (!m_fullscreenFrame) |
+ // The browser process can exit fullscreen at any time, e.g. if the user |
+ // presses Esc. After Browser::EnterFullscreenModeForTab, |
+ // Browser::ExitFullscreenModeForTab will make it seem like we exit when not |
+ // even in fullscreen. Do nothing. |
+ if (m_state == State::kInitial) |
return; |
- if (m_haveEnteredFullscreen) |
- updatePageScaleConstraints(true); |
- |
- if (Document* document = m_fullscreenFrame->document()) { |
- if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) { |
- Element* element = fullscreen->currentFullScreenElement(); |
- if (element) { |
- // When the client exits from full screen we have to call |
- // fullyExitFullscreen to notify the document. While doing that, |
- // suppress notifications back to the client. |
- m_isCancelingFullscreen = true; |
- Fullscreen::fullyExitFullscreen(*document); |
- m_isCancelingFullscreen = false; |
- |
- // We need to wait until style and layout are updated in order |
- // to propertly restore scroll offsets since content may not be |
- // overflowing in the same way until they do. |
- if (m_haveEnteredFullscreen) |
- m_needsScrollAndScaleRestore = true; |
+ updatePageScaleConstraints(true); |
+ |
+ // If we were transitioning into fullscreen, invoke the error callbacks. |
+ if (m_state == State::kEnteringFullscreen) { |
+ DCHECK(!m_callbacksList.isEmpty()); |
+ CallbacksList callbacksList; |
+ callbacksList.swap(m_callbacksList); |
+ for (auto& callbacks : callbacksList) |
esprehn
2016/12/01 20:26:12
Can we just move all of this logic down into core
foolip
2016/12/01 23:05:01
All of FullscreenController? In order to handle fu
|
+ callbacks->onError(); |
+ } else { |
+ DCHECK(m_callbacksList.isEmpty()); |
+ } |
+ // Set m_state so that any calls to enterFullscreen() or exitFullscreen() from |
+ // within Fullscreen::didExitFullscreen do nothing. |
+ m_state = State::kExitingFullscreen; |
+ |
+ // Notify all local frames that we have exited fullscreen. |
+ // TODO(foolip): This should only need to notify the topmost local roots. That |
+ // doesn't currently work because Fullscreen::m_currentFullScreenElement isn't |
+ // set for the topmost document when an iframe goes fullscreen, but can be |
+ // done once m_currentFullScreenElement is gone and all state is in the |
+ // fullscreen element stack. https://crbug.com/402421 |
+ for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame; |
+ frame = frame->tree().traverseNext()) { |
+ if (!frame->isLocalFrame()) |
+ continue; |
+ if (Document* document = toLocalFrame(frame)->document()) { |
+ if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) |
fullscreen->didExitFullscreen(); |
- } |
} |
} |
- m_haveEnteredFullscreen = false; |
- m_fullscreenFrame.clear(); |
+ // We need to wait until style and layout are updated in order to properly |
+ // restore scroll offsets since content may not be overflowing in the same way |
+ // until they are. |
+ m_state = State::kNeedsScrollAndScaleRestore; |
} |
-void FullscreenController::enterFullscreenForElement(Element* element) { |
- // We are already transitioning to fullscreen for a different element. |
- if (m_provisionalFullscreenElement) { |
- m_provisionalFullscreenElement = element; |
+namespace { |
+ |
+WebFrameClient& webFrameClient(LocalFrame& frame) { |
+ WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame); |
+ DCHECK(webFrame); |
+ DCHECK(webFrame->client()); |
+ return *webFrame->client(); |
+} |
+ |
+} // anonymous namespace |
+ |
+void FullscreenController::enterFullscreen( |
+ LocalFrame& frame, |
+ std::unique_ptr<FullscreenCallbacks> callbacks) { |
+ // If already in fullscreen, synchronously invoke the success callback. |
+ if (m_state == State::kFullscreen) { |
+ DCHECK(m_callbacksList.isEmpty()); |
+ callbacks->onSuccess(); |
return; |
} |
- // We are already in fullscreen mode. |
- if (m_fullscreenFrame) { |
- m_provisionalFullscreenElement = element; |
- didEnterFullscreen(); |
+ // While exiting fullscreen, reject any attempt to enter. |
+ if (m_state == State::kExitingFullscreen) { |
+ callbacks->onError(); |
return; |
} |
@@ -133,36 +154,38 @@ void FullscreenController::enterFullscreenForElement(Element* element) { |
// the scroll offset. Don't save values if we're still waiting to restore |
// a previous set. This can happen if we exit and quickly reenter fullscreen |
// without performing a layout. |
- if (!m_haveEnteredFullscreen && !m_needsScrollAndScaleRestore) { |
- m_exitFullscreenPageScaleFactor = m_webViewImpl->pageScaleFactor(); |
- m_exitFullscreenScrollOffset = |
- m_webViewImpl->mainFrame()->isWebLocalFrame() |
- ? m_webViewImpl->mainFrame()->scrollOffset() |
- : WebSize(); |
- m_exitFullscreenVisualViewportOffset = |
- m_webViewImpl->visualViewportOffset(); |
+ if (m_state == State::kInitial) { |
+ m_initialPageScaleFactor = m_webViewImpl->pageScaleFactor(); |
+ m_initialScrollOffset = m_webViewImpl->mainFrame()->isWebLocalFrame() |
+ ? m_webViewImpl->mainFrame()->scrollOffset() |
+ : WebSize(); |
+ m_initialVisualViewportOffset = m_webViewImpl->visualViewportOffset(); |
} |
- // We need to transition to fullscreen mode. |
- WebLocalFrameImpl* frame = |
- WebLocalFrameImpl::fromFrame(element->document().frame()); |
- if (frame && frame->client()) { |
- if (!Fullscreen::from(element->document()).forCrossProcessDescendant()) |
- frame->client()->enterFullscreen(); |
- m_provisionalFullscreenElement = element; |
- } |
-} |
+ m_callbacksList.append(std::move(callbacks)); |
-void FullscreenController::exitFullscreen(LocalFrame* frame) { |
- DCHECK(frame); |
+ // If already entering fullscreen, just wait. |
+ if (m_state == State::kEnteringFullscreen) |
+ return; |
- // The client is exiting full screen, so don't send a notification. |
- if (m_isCancelingFullscreen) |
+ DCHECK(m_state == State::kInitial || |
+ m_state == State::kNeedsScrollAndScaleRestore); |
+ webFrameClient(frame).enterFullscreen(); |
+ |
+ m_state = State::kEnteringFullscreen; |
+} |
+ |
+void FullscreenController::exitFullscreen(LocalFrame& frame) { |
+ // If not in fullscreen, ignore any attempt to exit. In particular, for |
+ // State::kEnteringFullscreen, allow the transition into fullscreen to |
+ // complete. Note that the browser process is ultimately in control and can |
+ // still (indirecitly) call didExitFullscreen() at any time to exit. |
+ if (m_state != State::kFullscreen) |
return; |
- WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame); |
- if (webFrame && webFrame->client()) |
- webFrame->client()->exitFullscreen(); |
+ webFrameClient(frame).exitFullscreen(); |
+ |
+ m_state = State::kExitingFullscreen; |
} |
void FullscreenController::fullscreenElementChanged(Element* fromElement, |
@@ -202,32 +225,38 @@ void FullscreenController::fullscreenElementChanged(Element* fromElement, |
} |
void FullscreenController::updateSize() { |
- if (!isFullscreen()) |
+ DCHECK(m_webViewImpl->page()); |
+ |
+ if (m_state != State::kFullscreen) |
return; |
updatePageScaleConstraints(false); |
- LayoutFullScreen* layoutObject = |
- Fullscreen::from(*m_fullscreenFrame->document()).fullScreenLayoutObject(); |
- if (layoutObject) |
- layoutObject->updateStyle(); |
+ // Traverse all local frames and notify the LayoutFullScreen object, if any. |
+ for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame; |
+ frame = frame->tree().traverseNext()) { |
+ if (!frame->isLocalFrame()) |
+ continue; |
+ if (Document* document = toLocalFrame(frame)->document()) { |
+ if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) { |
+ if (LayoutFullScreen* layoutObject = |
+ fullscreen->fullScreenLayoutObject()) |
+ layoutObject->updateStyle(); |
+ } |
+ } |
+ } |
} |
void FullscreenController::didUpdateLayout() { |
- if (!m_needsScrollAndScaleRestore) |
- return; |
- |
- // If we re-entered fullscreen before we could restore the scroll and scale |
- // don't try restoring them yet. |
- if (isFullscreen()) |
+ if (m_state != State::kNeedsScrollAndScaleRestore) |
return; |
- m_webViewImpl->setPageScaleFactor(m_exitFullscreenPageScaleFactor); |
+ m_webViewImpl->setPageScaleFactor(m_initialPageScaleFactor); |
if (m_webViewImpl->mainFrame()->isWebLocalFrame()) |
- m_webViewImpl->mainFrame()->setScrollOffset( |
- WebSize(m_exitFullscreenScrollOffset)); |
- m_webViewImpl->setVisualViewportOffset(m_exitFullscreenVisualViewportOffset); |
- m_needsScrollAndScaleRestore = false; |
+ m_webViewImpl->mainFrame()->setScrollOffset(WebSize(m_initialScrollOffset)); |
+ m_webViewImpl->setVisualViewportOffset(m_initialVisualViewportOffset); |
+ |
+ m_state = State::kInitial; |
} |
void FullscreenController::updatePageScaleConstraints(bool removeConstraints) { |
@@ -255,9 +284,4 @@ void FullscreenController::updatePageScaleConstraints(bool removeConstraints) { |
m_webViewImpl->updateMainFrameLayoutSize(); |
} |
-DEFINE_TRACE(FullscreenController) { |
- visitor->trace(m_provisionalFullscreenElement); |
- visitor->trace(m_fullscreenFrame); |
-} |
- |
} // namespace blink |