| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 #include "web/FullscreenController.h" | 31 #include "web/FullscreenController.h" |
| 32 | 32 |
| 33 #include "core/dom/Document.h" | 33 #include "core/dom/Document.h" |
| 34 #include "core/dom/Fullscreen.h" | 34 #include "core/dom/Fullscreen.h" |
| 35 #include "core/frame/FrameView.h" | 35 #include "core/frame/FrameView.h" |
| 36 #include "core/frame/LocalFrame.h" | 36 #include "core/frame/LocalFrame.h" |
| 37 #include "core/frame/PageScaleConstraintsSet.h" | 37 #include "core/frame/PageScaleConstraintsSet.h" |
| 38 #include "core/html/HTMLVideoElement.h" | 38 #include "core/html/HTMLVideoElement.h" |
| 39 #include "core/layout/LayoutFullScreen.h" | 39 #include "core/layout/LayoutFullScreen.h" |
| 40 #include "platform/RuntimeEnabledFeatures.h" | |
| 41 #include "public/platform/WebLayerTreeView.h" | 40 #include "public/platform/WebLayerTreeView.h" |
| 42 #include "public/web/WebFrameClient.h" | 41 #include "public/web/WebFrameClient.h" |
| 43 #include "web/WebLocalFrameImpl.h" | 42 #include "web/WebLocalFrameImpl.h" |
| 44 #include "web/WebSettingsImpl.h" | |
| 45 #include "web/WebViewImpl.h" | 43 #include "web/WebViewImpl.h" |
| 46 | 44 |
| 47 namespace blink { | 45 namespace blink { |
| 48 | 46 |
| 49 FullscreenController* FullscreenController::create(WebViewImpl* webViewImpl) { | 47 namespace { |
| 50 return new FullscreenController(webViewImpl); | 48 |
| 49 WebFrameClient& webFrameClient(LocalFrame& frame) { |
| 50 WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame); |
| 51 DCHECK(webFrame); |
| 52 DCHECK(webFrame->client()); |
| 53 return *webFrame->client(); |
| 54 } |
| 55 |
| 56 } // anonymous namespace |
| 57 |
| 58 std::unique_ptr<FullscreenController> FullscreenController::create( |
| 59 WebViewImpl* webViewImpl) { |
| 60 return wrapUnique(new FullscreenController(webViewImpl)); |
| 51 } | 61 } |
| 52 | 62 |
| 53 FullscreenController::FullscreenController(WebViewImpl* webViewImpl) | 63 FullscreenController::FullscreenController(WebViewImpl* webViewImpl) |
| 54 : m_webViewImpl(webViewImpl), | 64 : m_webViewImpl(webViewImpl) {} |
| 55 m_haveEnteredFullscreen(false), | |
| 56 m_exitFullscreenPageScaleFactor(0), | |
| 57 m_needsScrollAndScaleRestore(false), | |
| 58 m_isCancelingFullscreen(false) {} | |
| 59 | 65 |
| 60 void FullscreenController::didEnterFullscreen() { | 66 void FullscreenController::didEnterFullscreen() { |
| 61 if (!m_provisionalFullscreenElement) | 67 // |Browser::EnterFullscreenModeForTab()| can enter fullscreen without going |
| 68 // through |Fullscreen::requestFullscreen()|, in which case there will be no |
| 69 // fullscreen element. Do nothing. |
| 70 if (m_state != State::EnteringFullscreen) |
| 62 return; | 71 return; |
| 63 | 72 |
| 64 Element* element = m_provisionalFullscreenElement.release(); | 73 updatePageScaleConstraints(false); |
| 65 Document& document = element->document(); | 74 m_webViewImpl->setPageScaleFactor(1.0f); |
| 66 m_fullscreenFrame = document.frame(); | 75 if (m_webViewImpl->mainFrame()->isWebLocalFrame()) |
| 76 m_webViewImpl->mainFrame()->setScrollOffset(WebSize()); |
| 77 m_webViewImpl->setVisualViewportOffset(FloatPoint()); |
| 67 | 78 |
| 68 if (!m_fullscreenFrame) | 79 m_state = State::Fullscreen; |
| 69 return; | |
| 70 | 80 |
| 71 if (!m_haveEnteredFullscreen) { | 81 // Notify all local frames that we have entered fullscreen. |
| 72 updatePageScaleConstraints(false); | 82 for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame; |
| 73 m_webViewImpl->setPageScaleFactor(1.0f); | 83 frame = frame->tree().traverseNext()) { |
| 74 if (m_webViewImpl->mainFrame()->isWebLocalFrame()) | 84 if (!frame->isLocalFrame()) |
| 75 m_webViewImpl->mainFrame()->setScrollOffset(WebSize()); | 85 continue; |
| 76 m_webViewImpl->setVisualViewportOffset(FloatPoint()); | 86 if (Document* document = toLocalFrame(frame)->document()) { |
| 77 m_haveEnteredFullscreen = true; | 87 if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) |
| 88 fullscreen->didEnterFullscreen(); |
| 89 } |
| 78 } | 90 } |
| 79 | |
| 80 Fullscreen::from(document).didEnterFullscreenForElement(element); | |
| 81 DCHECK_EQ(Fullscreen::currentFullScreenElementFrom(document), element); | |
| 82 } | 91 } |
| 83 | 92 |
| 84 void FullscreenController::didExitFullscreen() { | 93 void FullscreenController::didExitFullscreen() { |
| 85 if (!m_fullscreenFrame) | 94 // The browser process can exit fullscreen at any time, e.g. if the user |
| 95 // presses Esc. After |Browser::EnterFullscreenModeForTab()|, |
| 96 // |Browser::ExitFullscreenModeForTab()| will make it seem like we exit when |
| 97 // not even in fullscreen. Do nothing. |
| 98 if (m_state == State::Initial) |
| 86 return; | 99 return; |
| 87 | 100 |
| 88 if (m_haveEnteredFullscreen) | 101 updatePageScaleConstraints(true); |
| 89 updatePageScaleConstraints(true); | |
| 90 | 102 |
| 91 if (Document* document = m_fullscreenFrame->document()) { | 103 // Set |m_state| so that any |exitFullscreen()| calls from within |
| 92 if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) { | 104 // |Fullscreen::didExitFullscreen()| do not call |
| 93 Element* element = fullscreen->currentFullScreenElement(); | 105 // |WebFrameClient::exitFullscreen()| again. |
| 94 if (element) { | 106 // TODO(foolip): Remove this when state changes and events are synchronized |
| 95 // When the client exits from full screen we have to call | 107 // with animation frames. https://crbug.com/402376 |
| 96 // fullyExitFullscreen to notify the document. While doing that, | 108 m_state = State::ExitingFullscreen; |
| 97 // suppress notifications back to the client. | |
| 98 m_isCancelingFullscreen = true; | |
| 99 Fullscreen::fullyExitFullscreen(*document); | |
| 100 m_isCancelingFullscreen = false; | |
| 101 | 109 |
| 102 // We need to wait until style and layout are updated in order | 110 // Notify all local frames that we have exited fullscreen. |
| 103 // to propertly restore scroll offsets since content may not be | 111 // TODO(foolip): This should only need to notify the topmost local roots. That |
| 104 // overflowing in the same way until they do. | 112 // doesn't currently work because |Fullscreen::m_currentFullScreenElement| |
| 105 if (m_haveEnteredFullscreen) | 113 // isn't set for the topmost document when an iframe goes fullscreen, but can |
| 106 m_needsScrollAndScaleRestore = true; | 114 // be done once |m_currentFullScreenElement| is gone and all state is in the |
| 107 | 115 // fullscreen element stack. https://crbug.com/402421 |
| 116 for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame; |
| 117 frame = frame->tree().traverseNext()) { |
| 118 if (!frame->isLocalFrame()) |
| 119 continue; |
| 120 if (Document* document = toLocalFrame(frame)->document()) { |
| 121 if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) |
| 108 fullscreen->didExitFullscreen(); | 122 fullscreen->didExitFullscreen(); |
| 109 } | |
| 110 } | 123 } |
| 111 } | 124 } |
| 112 | 125 |
| 113 m_haveEnteredFullscreen = false; | 126 // We need to wait until style and layout are updated in order to properly |
| 114 m_fullscreenFrame.clear(); | 127 // restore scroll offsets since content may not be overflowing in the same way |
| 128 // until they are. |
| 129 m_state = State::NeedsScrollAndScaleRestore; |
| 115 } | 130 } |
| 116 | 131 |
| 117 void FullscreenController::enterFullscreenForElement(Element* element) { | 132 void FullscreenController::enterFullscreen(LocalFrame& frame) { |
| 118 // We are already transitioning to fullscreen for a different element. | 133 // If already fullscreen or exiting fullscreen, synchronously call |
| 119 if (m_provisionalFullscreenElement) { | 134 // |didEnterFullscreen()|. When exiting, the coming |didExitFullscren()| call |
| 120 m_provisionalFullscreenElement = element; | 135 // will again notify all frames. |
| 136 if (m_state == State::Fullscreen || m_state == State::ExitingFullscreen) { |
| 137 State oldState = m_state; |
| 138 m_state = State::EnteringFullscreen; |
| 139 didEnterFullscreen(); |
| 140 m_state = oldState; |
| 121 return; | 141 return; |
| 122 } | 142 } |
| 123 | 143 |
| 124 // We are already in fullscreen mode. | 144 // We need to store these values here rather than in |didEnterFullscreen()| |
| 125 if (m_fullscreenFrame) { | 145 // since by the time the latter is called, a Resize has already occured, |
| 126 m_provisionalFullscreenElement = element; | 146 // clamping the scroll offset. Don't save values if we're still waiting to |
| 127 didEnterFullscreen(); | 147 // restore a previous set. This can happen if we exit and quickly reenter |
| 128 return; | 148 // fullscreen without performing a layout. |
| 149 if (m_state == State::Initial) { |
| 150 m_initialPageScaleFactor = m_webViewImpl->pageScaleFactor(); |
| 151 m_initialScrollOffset = m_webViewImpl->mainFrame()->isWebLocalFrame() |
| 152 ? m_webViewImpl->mainFrame()->getScrollOffset() |
| 153 : WebSize(); |
| 154 m_initialVisualViewportOffset = m_webViewImpl->visualViewportOffset(); |
| 129 } | 155 } |
| 130 | 156 |
| 131 // We need to store these values here rather than didEnterFullscreen since | 157 // If already entering fullscreen, just wait. |
| 132 // by the time the latter is called, a Resize has already occured, clamping | 158 if (m_state == State::EnteringFullscreen) |
| 133 // the scroll offset. Don't save values if we're still waiting to restore | 159 return; |
| 134 // a previous set. This can happen if we exit and quickly reenter fullscreen | |
| 135 // without performing a layout. | |
| 136 if (!m_haveEnteredFullscreen && !m_needsScrollAndScaleRestore) { | |
| 137 m_exitFullscreenPageScaleFactor = m_webViewImpl->pageScaleFactor(); | |
| 138 m_exitFullscreenScrollOffset = | |
| 139 m_webViewImpl->mainFrame()->isWebLocalFrame() | |
| 140 ? m_webViewImpl->mainFrame()->getScrollOffset() | |
| 141 : WebSize(); | |
| 142 m_exitFullscreenVisualViewportOffset = | |
| 143 m_webViewImpl->visualViewportOffset(); | |
| 144 } | |
| 145 | 160 |
| 146 // We need to transition to fullscreen mode. | 161 DCHECK(m_state == State::Initial || |
| 147 WebLocalFrameImpl* frame = | 162 m_state == State::NeedsScrollAndScaleRestore); |
| 148 WebLocalFrameImpl::fromFrame(element->document().frame()); | 163 webFrameClient(frame).enterFullscreen(); |
| 149 if (frame && frame->client()) { | 164 |
| 150 if (!Fullscreen::from(element->document()).forCrossProcessDescendant()) | 165 m_state = State::EnteringFullscreen; |
| 151 frame->client()->enterFullscreen(); | |
| 152 m_provisionalFullscreenElement = element; | |
| 153 } | |
| 154 } | 166 } |
| 155 | 167 |
| 156 void FullscreenController::exitFullscreen(LocalFrame* frame) { | 168 void FullscreenController::exitFullscreen(LocalFrame& frame) { |
| 157 DCHECK(frame); | 169 // If not in fullscreen, ignore any attempt to exit. In particular, when |
| 158 | 170 // entering fullscreen, allow the transition into fullscreen to complete. Note |
| 159 // The client is exiting full screen, so don't send a notification. | 171 // that the browser process is ultimately in control and can still exit |
| 160 if (m_isCancelingFullscreen) | 172 // fullscreen at any time. |
| 173 if (m_state != State::Fullscreen) |
| 161 return; | 174 return; |
| 162 | 175 |
| 163 WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame); | 176 webFrameClient(frame).exitFullscreen(); |
| 164 if (webFrame && webFrame->client()) | 177 |
| 165 webFrame->client()->exitFullscreen(); | 178 m_state = State::ExitingFullscreen; |
| 166 } | 179 } |
| 167 | 180 |
| 168 void FullscreenController::fullscreenElementChanged(Element* fromElement, | 181 void FullscreenController::fullscreenElementChanged(Element* fromElement, |
| 169 Element* toElement) { | 182 Element* toElement) { |
| 170 DCHECK_NE(fromElement, toElement); | 183 DCHECK_NE(fromElement, toElement); |
| 171 | 184 |
| 172 if (toElement) { | 185 if (toElement) { |
| 173 DCHECK(Fullscreen::isCurrentFullScreenElement(*toElement)); | 186 DCHECK(Fullscreen::isCurrentFullScreenElement(*toElement)); |
| 174 | 187 |
| 175 if (isHTMLVideoElement(*toElement)) { | 188 if (isHTMLVideoElement(*toElement)) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 195 m_webViewImpl->isTransparent()); | 208 m_webViewImpl->isTransparent()); |
| 196 } | 209 } |
| 197 | 210 |
| 198 HTMLVideoElement& videoElement = toHTMLVideoElement(*fromElement); | 211 HTMLVideoElement& videoElement = toHTMLVideoElement(*fromElement); |
| 199 videoElement.didExitFullscreen(); | 212 videoElement.didExitFullscreen(); |
| 200 } | 213 } |
| 201 } | 214 } |
| 202 } | 215 } |
| 203 | 216 |
| 204 void FullscreenController::updateSize() { | 217 void FullscreenController::updateSize() { |
| 205 if (!isFullscreen()) | 218 DCHECK(m_webViewImpl->page()); |
| 219 |
| 220 if (m_state != State::Fullscreen) |
| 206 return; | 221 return; |
| 207 | 222 |
| 208 updatePageScaleConstraints(false); | 223 updatePageScaleConstraints(false); |
| 209 | 224 |
| 210 LayoutFullScreen* layoutObject = | 225 // Traverse all local frames and notify the LayoutFullScreen object, if any. |
| 211 Fullscreen::from(*m_fullscreenFrame->document()).fullScreenLayoutObject(); | 226 for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame; |
| 212 if (layoutObject) | 227 frame = frame->tree().traverseNext()) { |
| 213 layoutObject->updateStyle(); | 228 if (!frame->isLocalFrame()) |
| 229 continue; |
| 230 if (Document* document = toLocalFrame(frame)->document()) { |
| 231 if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document)) { |
| 232 if (LayoutFullScreen* layoutObject = |
| 233 fullscreen->fullScreenLayoutObject()) |
| 234 layoutObject->updateStyle(); |
| 235 } |
| 236 } |
| 237 } |
| 214 } | 238 } |
| 215 | 239 |
| 216 void FullscreenController::didUpdateLayout() { | 240 void FullscreenController::didUpdateLayout() { |
| 217 if (!m_needsScrollAndScaleRestore) | 241 if (m_state != State::NeedsScrollAndScaleRestore) |
| 218 return; | 242 return; |
| 219 | 243 |
| 220 // If we re-entered fullscreen before we could restore the scroll and scale | 244 m_webViewImpl->setPageScaleFactor(m_initialPageScaleFactor); |
| 221 // don't try restoring them yet. | 245 if (m_webViewImpl->mainFrame()->isWebLocalFrame()) |
| 222 if (isFullscreen()) | 246 m_webViewImpl->mainFrame()->setScrollOffset(WebSize(m_initialScrollOffset)); |
| 223 return; | 247 m_webViewImpl->setVisualViewportOffset(m_initialVisualViewportOffset); |
| 224 | 248 |
| 225 m_webViewImpl->setPageScaleFactor(m_exitFullscreenPageScaleFactor); | 249 m_state = State::Initial; |
| 226 if (m_webViewImpl->mainFrame()->isWebLocalFrame()) | |
| 227 m_webViewImpl->mainFrame()->setScrollOffset( | |
| 228 WebSize(m_exitFullscreenScrollOffset)); | |
| 229 m_webViewImpl->setVisualViewportOffset(m_exitFullscreenVisualViewportOffset); | |
| 230 m_needsScrollAndScaleRestore = false; | |
| 231 } | 250 } |
| 232 | 251 |
| 233 void FullscreenController::updatePageScaleConstraints(bool removeConstraints) { | 252 void FullscreenController::updatePageScaleConstraints(bool removeConstraints) { |
| 234 PageScaleConstraints fullscreenConstraints; | 253 PageScaleConstraints fullscreenConstraints; |
| 235 if (!removeConstraints) { | 254 if (!removeConstraints) { |
| 236 fullscreenConstraints = PageScaleConstraints(1.0, 1.0, 1.0); | 255 fullscreenConstraints = PageScaleConstraints(1.0, 1.0, 1.0); |
| 237 fullscreenConstraints.layoutSize = FloatSize(m_webViewImpl->size()); | 256 fullscreenConstraints.layoutSize = FloatSize(m_webViewImpl->size()); |
| 238 } | 257 } |
| 239 m_webViewImpl->pageScaleConstraintsSet().setFullscreenConstraints( | 258 m_webViewImpl->pageScaleConstraintsSet().setFullscreenConstraints( |
| 240 fullscreenConstraints); | 259 fullscreenConstraints); |
| 241 m_webViewImpl->pageScaleConstraintsSet().computeFinalConstraints(); | 260 m_webViewImpl->pageScaleConstraintsSet().computeFinalConstraints(); |
| 242 | 261 |
| 243 // Although we called computedFinalConstraints() above, the "final" | 262 // Although we called |computedFinalConstraints()| above, the "final" |
| 244 // constraints are not actually final. They are still subject to scale factor | 263 // constraints are not actually final. They are still subject to scale factor |
| 245 // clamping by contents size. Normally they should be dirtied due to | 264 // clamping by contents size. Normally they should be dirtied due to contents |
| 246 // contents size mutation after layout, however the contents size is not | 265 // size mutation after layout, however the contents size is not guaranteed to |
| 247 // guaranteed to mutate, and the scale factor may remain unclamped. Just | 266 // mutate, and the scale factor may remain unclamped. Just fire the event |
| 248 // fire the event again to ensure the final constraints pick up the latest | 267 // again to ensure the final constraints pick up the latest contents size. |
| 249 // contents size. | |
| 250 m_webViewImpl->didChangeContentsSize(); | 268 m_webViewImpl->didChangeContentsSize(); |
| 251 if (m_webViewImpl->mainFrameImpl() && | 269 if (m_webViewImpl->mainFrameImpl() && |
| 252 m_webViewImpl->mainFrameImpl()->frameView()) | 270 m_webViewImpl->mainFrameImpl()->frameView()) |
| 253 m_webViewImpl->mainFrameImpl()->frameView()->setNeedsLayout(); | 271 m_webViewImpl->mainFrameImpl()->frameView()->setNeedsLayout(); |
| 254 | 272 |
| 255 m_webViewImpl->updateMainFrameLayoutSize(); | 273 m_webViewImpl->updateMainFrameLayoutSize(); |
| 256 } | 274 } |
| 257 | 275 |
| 258 DEFINE_TRACE(FullscreenController) { | |
| 259 visitor->trace(m_provisionalFullscreenElement); | |
| 260 visitor->trace(m_fullscreenFrame); | |
| 261 } | |
| 262 | |
| 263 } // namespace blink | 276 } // namespace blink |
| OLD | NEW |