1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25#include "config.h"
26#include "WebFullScreenManager.h"
27
28#if ENABLE(FULLSCREEN_API)
29
30#include "Connection.h"
31#include "Logging.h"
32#include "WebCoreArgumentCoders.h"
33#include "WebFrame.h"
34#include "WebFullScreenManagerProxyMessages.h"
35#include "WebPage.h"
36#include <WebCore/Color.h>
37#include <WebCore/Element.h>
38#include <WebCore/Frame.h>
39#include <WebCore/FrameView.h>
40#include <WebCore/FullscreenManager.h>
41#include <WebCore/HTMLVideoElement.h>
42#include <WebCore/Page.h>
43#include <WebCore/RenderLayer.h>
44#include <WebCore/RenderLayerBacking.h>
45#include <WebCore/RenderObject.h>
46#include <WebCore/RenderView.h>
47#include <WebCore/Settings.h>
48#include <WebCore/TypedElementDescendantIterator.h>
49
50#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
51#include "PlaybackSessionManager.h"
52#endif
53
54namespace WebKit {
55using namespace WebCore;
56
57static IntRect screenRectOfContents(Element* element)
58{
59 ASSERT(element);
60 if (element->renderer() && element->renderer()->hasLayer() && element->renderer()->enclosingLayer()->isComposited()) {
61 FloatQuad contentsBox = static_cast<FloatRect>(element->renderer()->enclosingLayer()->backing()->contentsBox());
62 contentsBox = element->renderer()->localToAbsoluteQuad(contentsBox);
63 return element->renderer()->view().frameView().contentsToScreen(contentsBox.enclosingBoundingBox());
64 }
65
66 return element->screenRect();
67}
68
69Ref<WebFullScreenManager> WebFullScreenManager::create(WebPage* page)
70{
71 return adoptRef(*new WebFullScreenManager(page));
72}
73
74WebFullScreenManager::WebFullScreenManager(WebPage* page)
75 : m_page(page)
76{
77}
78
79WebFullScreenManager::~WebFullScreenManager()
80{
81}
82
83WebCore::Element* WebFullScreenManager::element()
84{
85 return m_element.get();
86}
87
88void WebFullScreenManager::videoControlsManagerDidChange()
89{
90#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
91 LOG(Fullscreen, "WebFullScreenManager %p videoControlsManagerDidChange()", this);
92
93 auto* currentPlaybackControlsElement = m_page->playbackSessionManager().currentPlaybackControlsElement();
94 if (!m_element || !is<HTMLVideoElement>(currentPlaybackControlsElement)) {
95 setPIPStandbyElement(nullptr);
96 return;
97 }
98
99 setPIPStandbyElement(downcast<HTMLVideoElement>(currentPlaybackControlsElement));
100#endif
101}
102
103void WebFullScreenManager::setPIPStandbyElement(WebCore::HTMLVideoElement* pipStandbyElement)
104{
105#if ENABLE(VIDEO)
106 if (pipStandbyElement == m_pipStandbyElement)
107 return;
108
109 LOG(Fullscreen, "WebFullScreenManager %p setPIPStandbyElement() - old element %p, new element %p", this, m_pipStandbyElement.get(), pipStandbyElement);
110
111 if (m_pipStandbyElement)
112 m_pipStandbyElement->setVideoFullscreenStandby(false);
113
114 m_pipStandbyElement = pipStandbyElement;
115
116 if (m_pipStandbyElement)
117 m_pipStandbyElement->setVideoFullscreenStandby(true);
118#endif
119}
120
121void WebFullScreenManager::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
122{
123 didReceiveWebFullScreenManagerMessage(connection, decoder);
124}
125
126bool WebFullScreenManager::supportsFullScreen(bool withKeyboard)
127{
128 if (!m_page->corePage()->settings().fullScreenEnabled())
129 return false;
130
131 return m_page->injectedBundleFullScreenClient().supportsFullScreen(m_page.get(), withKeyboard);
132}
133
134void WebFullScreenManager::enterFullScreenForElement(WebCore::Element* element)
135{
136 LOG(Fullscreen, "WebFullScreenManager %p enterFullScreenForElement(%p)", this, element);
137
138 ASSERT(element);
139 m_element = element;
140 m_initialFrame = screenRectOfContents(m_element.get());
141 m_page->injectedBundleFullScreenClient().enterFullScreenForElement(m_page.get(), element);
142}
143
144void WebFullScreenManager::exitFullScreenForElement(WebCore::Element* element)
145{
146 LOG(Fullscreen, "WebFullScreenManager %p exitFullScreenForElement(%p) - fullscreen element %p", this, element, m_element.get());
147 m_page->injectedBundleFullScreenClient().exitFullScreenForElement(m_page.get(), element);
148}
149
150void WebFullScreenManager::willEnterFullScreen()
151{
152 LOG(Fullscreen, "WebFullScreenManager %p willEnterFullScreen() - element %p", this, m_element.get());
153
154 m_element->document().fullscreenManager().willEnterFullscreen(*m_element);
155#if !PLATFORM(IOS_FAMILY)
156 m_page->hidePageBanners();
157#endif
158 m_element->document().updateLayout();
159 m_page->forceRepaintWithoutCallback();
160 m_finalFrame = screenRectOfContents(m_element.get());
161 m_page->injectedBundleFullScreenClient().beganEnterFullScreen(m_page.get(), m_initialFrame, m_finalFrame);
162}
163
164void WebFullScreenManager::didEnterFullScreen()
165{
166 LOG(Fullscreen, "WebFullScreenManager %p didEnterFullScreen() - element %p", this, m_element.get());
167
168 m_element->document().fullscreenManager().didEnterFullscreen();
169
170#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
171 auto* currentPlaybackControlsElement = m_page->playbackSessionManager().currentPlaybackControlsElement();
172 setPIPStandbyElement(is<HTMLVideoElement>(currentPlaybackControlsElement) ? downcast<HTMLVideoElement>(currentPlaybackControlsElement) : nullptr);
173#endif
174}
175
176void WebFullScreenManager::willExitFullScreen()
177{
178 LOG(Fullscreen, "WebFullScreenManager %p willExitFullScreen() - element %p", this, m_element.get());
179 ASSERT(m_element);
180
181#if ENABLE(VIDEO)
182 setPIPStandbyElement(nullptr);
183#endif
184
185 m_finalFrame = screenRectOfContents(m_element.get());
186 m_element->document().fullscreenManager().willExitFullscreen();
187#if !PLATFORM(IOS_FAMILY)
188 m_page->showPageBanners();
189#endif
190 m_page->injectedBundleFullScreenClient().beganExitFullScreen(m_page.get(), m_finalFrame, m_initialFrame);
191}
192
193void WebFullScreenManager::didExitFullScreen()
194{
195 LOG(Fullscreen, "WebFullScreenManager %p didExitFullScreen() - element %p", this, m_element.get());
196
197 ASSERT(m_element);
198 setFullscreenInsets(FloatBoxExtent());
199 setFullscreenAutoHideDuration(0_s);
200 m_element->document().fullscreenManager().didExitFullscreen();
201}
202
203void WebFullScreenManager::setAnimatingFullScreen(bool animating)
204{
205 ASSERT(m_element);
206 m_element->document().fullscreenManager().setAnimatingFullscreen(animating);
207}
208
209void WebFullScreenManager::requestExitFullScreen()
210{
211 ASSERT(m_element);
212 m_element->document().fullscreenManager().cancelFullscreen();
213}
214
215void WebFullScreenManager::close()
216{
217 LOG(Fullscreen, "WebFullScreenManager %p close()", this);
218 m_page->injectedBundleFullScreenClient().closeFullScreen(m_page.get());
219}
220
221void WebFullScreenManager::saveScrollPosition()
222{
223 m_scrollPosition = m_page->corePage()->mainFrame().view()->scrollPosition();
224}
225
226void WebFullScreenManager::restoreScrollPosition()
227{
228 m_page->corePage()->mainFrame().view()->setScrollPosition(m_scrollPosition);
229}
230
231void WebFullScreenManager::setFullscreenInsets(const WebCore::FloatBoxExtent& insets)
232{
233 m_page->corePage()->setFullscreenInsets(insets);
234}
235
236void WebFullScreenManager::setFullscreenAutoHideDuration(Seconds duration)
237{
238 m_page->corePage()->setFullscreenAutoHideDuration(duration);
239}
240
241void WebFullScreenManager::setFullscreenControlsHidden(bool hidden)
242{
243 m_page->corePage()->setFullscreenControlsHidden(hidden);
244}
245
246} // namespace WebKit
247
248#endif // ENABLE(FULLSCREEN_API)
249