| 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 63c52024dcb6051ff2078f3daaf0e7ee7a2d0b7b..c139da43cda4d5410e0653d25ccd86930ec70feb 100644
|
| --- a/third_party/WebKit/Source/web/FullscreenController.cpp
|
| +++ b/third_party/WebKit/Source/web/FullscreenController.cpp
|
| @@ -37,132 +37,145 @@
|
| #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);
|
| +namespace {
|
| +
|
| +WebFrameClient& webFrameClient(LocalFrame& frame) {
|
| + WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame);
|
| + DCHECK(webFrame);
|
| + DCHECK(webFrame->client());
|
| + return *webFrame->client();
|
| }
|
|
|
| -FullscreenController::FullscreenController(WebViewImpl* webViewImpl)
|
| - : m_webViewImpl(webViewImpl),
|
| - m_haveEnteredFullscreen(false),
|
| - m_exitFullscreenPageScaleFactor(0),
|
| - m_needsScrollAndScaleRestore(false),
|
| - m_isCancelingFullscreen(false) {}
|
| +} // anonymous namespace
|
|
|
| -void FullscreenController::didEnterFullscreen() {
|
| - if (!m_provisionalFullscreenElement)
|
| - return;
|
| +std::unique_ptr<FullscreenController> FullscreenController::create(
|
| + WebViewImpl* webViewImpl) {
|
| + return wrapUnique(new FullscreenController(webViewImpl));
|
| +}
|
|
|
| - Element* element = m_provisionalFullscreenElement.release();
|
| - Document& document = element->document();
|
| - m_fullscreenFrame = document.frame();
|
| +FullscreenController::FullscreenController(WebViewImpl* webViewImpl)
|
| + : m_webViewImpl(webViewImpl) {}
|
|
|
| - if (!m_fullscreenFrame)
|
| +void FullscreenController::didEnterFullscreen() {
|
| + // |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::EnteringFullscreen)
|
| return;
|
|
|
| - 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;
|
| + updatePageScaleConstraints(false);
|
| + m_webViewImpl->setPageScaleFactor(1.0f);
|
| + if (m_webViewImpl->mainFrame()->isWebLocalFrame())
|
| + m_webViewImpl->mainFrame()->setScrollOffset(WebSize());
|
| + m_webViewImpl->setVisualViewportOffset(FloatPoint());
|
| +
|
| + m_state = State::Fullscreen;
|
| +
|
| + // Notify all local frames that we have entered fullscreen.
|
| + 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->didEnterFullscreen();
|
| + }
|
| }
|
| -
|
| - Fullscreen::from(document).didEnterFullscreenForElement(element);
|
| - DCHECK_EQ(Fullscreen::currentFullScreenElementFrom(document), element);
|
| }
|
|
|
| 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::Initial)
|
| 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);
|
| +
|
| + // Set |m_state| so that any |exitFullscreen()| calls from within
|
| + // |Fullscreen::didExitFullscreen()| do not call
|
| + // |WebFrameClient::exitFullscreen()| again.
|
| + // TODO(foolip): Remove this when state changes and events are synchronized
|
| + // with animation frames. https://crbug.com/402376
|
| + m_state = State::ExitingFullscreen;
|
| +
|
| + // 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::NeedsScrollAndScaleRestore;
|
| }
|
|
|
| -void FullscreenController::enterFullscreenForElement(Element* element) {
|
| - // We are already transitioning to fullscreen for a different element.
|
| - if (m_provisionalFullscreenElement) {
|
| - m_provisionalFullscreenElement = element;
|
| - return;
|
| - }
|
| -
|
| - // We are already in fullscreen mode.
|
| - if (m_fullscreenFrame) {
|
| - m_provisionalFullscreenElement = element;
|
| +void FullscreenController::enterFullscreen(LocalFrame& frame) {
|
| + // If already fullscreen or exiting fullscreen, synchronously call
|
| + // |didEnterFullscreen()|. When exiting, the coming |didExitFullscren()| call
|
| + // will again notify all frames.
|
| + if (m_state == State::Fullscreen || m_state == State::ExitingFullscreen) {
|
| + State oldState = m_state;
|
| + m_state = State::EnteringFullscreen;
|
| didEnterFullscreen();
|
| + m_state = oldState;
|
| return;
|
| }
|
|
|
| - // We need to store these values here rather than didEnterFullscreen since
|
| - // by the time the latter is called, a Resize has already occured, clamping
|
| - // 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()->getScrollOffset()
|
| - : WebSize();
|
| - m_exitFullscreenVisualViewportOffset =
|
| - m_webViewImpl->visualViewportOffset();
|
| + // We need to store these values here rather than in |didEnterFullscreen()|
|
| + // since by the time the latter is called, a Resize has already occured,
|
| + // clamping 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_state == State::Initial) {
|
| + m_initialPageScaleFactor = m_webViewImpl->pageScaleFactor();
|
| + m_initialScrollOffset = m_webViewImpl->mainFrame()->isWebLocalFrame()
|
| + ? m_webViewImpl->mainFrame()->getScrollOffset()
|
| + : 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;
|
| - }
|
| -}
|
| + // If already entering fullscreen, just wait.
|
| + if (m_state == State::EnteringFullscreen)
|
| + return;
|
| +
|
| + DCHECK(m_state == State::Initial ||
|
| + m_state == State::NeedsScrollAndScaleRestore);
|
| + webFrameClient(frame).enterFullscreen();
|
|
|
| -void FullscreenController::exitFullscreen(LocalFrame* frame) {
|
| - DCHECK(frame);
|
| + m_state = State::EnteringFullscreen;
|
| +}
|
|
|
| - // The client is exiting full screen, so don't send a notification.
|
| - if (m_isCancelingFullscreen)
|
| +void FullscreenController::exitFullscreen(LocalFrame& frame) {
|
| + // If not in fullscreen, ignore any attempt to exit. In particular, when
|
| + // entering fullscreen, allow the transition into fullscreen to complete. Note
|
| + // that the browser process is ultimately in control and can still exit
|
| + // fullscreen at any time.
|
| + if (m_state != State::Fullscreen)
|
| return;
|
|
|
| - WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame);
|
| - if (webFrame && webFrame->client())
|
| - webFrame->client()->exitFullscreen();
|
| + webFrameClient(frame).exitFullscreen();
|
| +
|
| + m_state = State::ExitingFullscreen;
|
| }
|
|
|
| void FullscreenController::fullscreenElementChanged(Element* fromElement,
|
| @@ -202,32 +215,38 @@ void FullscreenController::fullscreenElementChanged(Element* fromElement,
|
| }
|
|
|
| void FullscreenController::updateSize() {
|
| - if (!isFullscreen())
|
| + DCHECK(m_webViewImpl->page());
|
| +
|
| + if (m_state != State::Fullscreen)
|
| 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::NeedsScrollAndScaleRestore)
|
| 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::Initial;
|
| }
|
|
|
| void FullscreenController::updatePageScaleConstraints(bool removeConstraints) {
|
| @@ -240,13 +259,12 @@ void FullscreenController::updatePageScaleConstraints(bool removeConstraints) {
|
| fullscreenConstraints);
|
| m_webViewImpl->pageScaleConstraintsSet().computeFinalConstraints();
|
|
|
| - // Although we called computedFinalConstraints() above, the "final"
|
| + // Although we called |computedFinalConstraints()| above, the "final"
|
| // constraints are not actually final. They are still subject to scale factor
|
| - // clamping by contents size. Normally they should be dirtied due to
|
| - // contents size mutation after layout, however the contents size is not
|
| - // guaranteed to mutate, and the scale factor may remain unclamped. Just
|
| - // fire the event again to ensure the final constraints pick up the latest
|
| - // contents size.
|
| + // clamping by contents size. Normally they should be dirtied due to contents
|
| + // size mutation after layout, however the contents size is not guaranteed to
|
| + // mutate, and the scale factor may remain unclamped. Just fire the event
|
| + // again to ensure the final constraints pick up the latest contents size.
|
| m_webViewImpl->didChangeContentsSize();
|
| if (m_webViewImpl->mainFrameImpl() &&
|
| m_webViewImpl->mainFrameImpl()->frameView())
|
| @@ -255,9 +273,4 @@ void FullscreenController::updatePageScaleConstraints(bool removeConstraints) {
|
| m_webViewImpl->updateMainFrameLayoutSize();
|
| }
|
|
|
| -DEFINE_TRACE(FullscreenController) {
|
| - visitor->trace(m_provisionalFullscreenElement);
|
| - visitor->trace(m_fullscreenFrame);
|
| -}
|
| -
|
| } // namespace blink
|
|
|