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 |