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