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 |