Chromium Code Reviews| 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 |