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