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 |