1/* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) Research In Motion Limited 2009. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28 29#if ENABLE(FULLSCREEN_API) 30 31#include "FullScreenController.h" 32 33#include "Element.h" 34#include "FullScreenControllerClient.h" 35#include "IntRect.h" 36#include "MediaPlayerPrivateFullscreenWindow.h" 37#include "Timer.h" 38#include "WebCoreInstanceHandle.h" 39#include <wtf/RefPtr.h> 40 41using namespace WebCore; 42 43static const int kFullScreenAnimationDuration = 500; // milliseconds 44 45class FullScreenController::Private : public MediaPlayerPrivateFullscreenClient { 46public: 47 Private(FullScreenController* controller, FullScreenControllerClient* client) 48 : m_controller(controller) 49 , m_client(client) 50 , m_originalHost(0) 51 , m_isFullScreen(false) 52 , m_isEnteringFullScreen(false) 53 , m_isExitingFullScreen(false) 54 { 55 } 56 virtual ~Private() { } 57 58 virtual LRESULT fullscreenClientWndProc(HWND, UINT, WPARAM, LPARAM); 59 60 FullScreenController* m_controller; 61 FullScreenControllerClient* m_client; 62 OwnPtr<MediaPlayerPrivateFullscreenWindow> m_fullScreenWindow; 63 OwnPtr<MediaPlayerPrivateFullscreenWindow> m_backgroundWindow; 64 IntRect m_fullScreenFrame; 65 IntRect m_originalFrame; 66 HWND m_originalHost; 67 bool m_isFullScreen; 68 bool m_isEnteringFullScreen; 69 bool m_isExitingFullScreen; 70}; 71 72LRESULT FullScreenController::Private::fullscreenClientWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 73{ 74 LRESULT lResult = 0; 75 76 switch (msg) { 77 case WM_MOVE: 78 m_fullScreenFrame.setX(LOWORD(lParam)); 79 m_fullScreenFrame.setY(HIWORD(lParam)); 80 break; 81 case WM_SIZE: 82 m_fullScreenFrame.setWidth(LOWORD(lParam)); 83 m_fullScreenFrame.setHeight(HIWORD(lParam)); 84 if (m_client->fullScreenClientWindow()) 85 ::SetWindowPos(m_client->fullScreenClientWindow(), 0, 0, 0, m_fullScreenFrame.width(), m_fullScreenFrame.height(), SWP_NOREPOSITION | SWP_NOMOVE); 86 break; 87 case WM_ACTIVATE: 88 // Because m_fullScreenWindow is a topmost window, we need to exit full screen explicitly when it's deactivated. 89 if (!wParam && m_fullScreenWindow && (hwnd == m_fullScreenWindow->hwnd())) 90 m_controller->exitFullScreen(); 91 break; 92 case WM_KEYDOWN: 93 if (wParam == VK_ESCAPE) { 94 m_controller->exitFullScreen(); 95 break; 96 } 97 FALLTHROUGH; 98 default: 99 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); 100 } 101 102 return lResult; 103} 104 105FullScreenController::FullScreenController(FullScreenControllerClient* client) 106 : m_private(adoptPtr(new FullScreenController::Private(this, client))) 107{ 108 ASSERT_ARG(client, client); 109} 110 111FullScreenController::~FullScreenController() 112{ 113} 114 115bool FullScreenController::isFullScreen() const 116{ 117 return m_private->m_isFullScreen; 118} 119 120void FullScreenController::enterFullScreen() 121{ 122 if (m_private->m_isFullScreen || m_private->m_isEnteringFullScreen) 123 return; 124 m_private->m_isFullScreen = true; 125 m_private->m_isEnteringFullScreen = true; 126 127 m_private->m_client->fullScreenClientSaveScrollPosition(); 128 129 m_private->m_originalHost = m_private->m_client->fullScreenClientParentWindow(); 130 RECT originalFrame = {0, 0, 0, 0}; 131 ::GetClientRect(m_private->m_client->fullScreenClientWindow(), &originalFrame); 132 ::MapWindowPoints(m_private->m_client->fullScreenClientWindow(), m_private->m_originalHost, reinterpret_cast<LPPOINT>(&originalFrame), 2); 133 m_private->m_originalFrame = originalFrame; 134 135 ASSERT(!m_private->m_backgroundWindow); 136 m_private->m_backgroundWindow = adoptPtr(new MediaPlayerPrivateFullscreenWindow(m_private.get())); 137 m_private->m_backgroundWindow->createWindow(0); 138 ::AnimateWindow(m_private->m_backgroundWindow->hwnd(), kFullScreenAnimationDuration, AW_BLEND | AW_ACTIVATE); 139 140 m_private->m_client->fullScreenClientWillEnterFullScreen(); 141 ASSERT(!m_private->m_fullScreenWindow); 142 m_private->m_fullScreenWindow = adoptPtr(new MediaPlayerPrivateFullscreenWindow(m_private.get())); 143 ASSERT(m_private->m_fullScreenWindow); 144 m_private->m_fullScreenWindow->createWindow(0); 145 146 m_private->m_client->fullScreenClientSetParentWindow(m_private->m_fullScreenWindow->hwnd()); 147 148 IntRect viewFrame(IntPoint(), m_private->m_fullScreenFrame.size()); 149 ::SetWindowPos(m_private->m_fullScreenWindow->hwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 150 ::SetWindowPos(m_private->m_client->fullScreenClientWindow(), HWND_TOP, 0, 0, viewFrame.width(), viewFrame.height(), SWP_NOACTIVATE); 151 152 m_private->m_client->fullScreenClientDidEnterFullScreen(); 153 m_private->m_client->fullScreenClientForceRepaint(); 154} 155 156void FullScreenController::enterFullScreenRepaintCompleted() 157{ 158 if (!m_private->m_isEnteringFullScreen) 159 return; 160 m_private->m_isEnteringFullScreen = false; 161 162 // Normally, when the background fullscreen window is animated in, the Windows taskbar will be hidden, but this doesn't always work for some reason. 163 // Setting the real fullscreen window to be a topmost window will force the taskbar to be hidden when we call AnimateWindow() below if it wasn't before. 164 ::SetWindowPos(m_private->m_fullScreenWindow->hwnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 165 ::AnimateWindow(m_private->m_fullScreenWindow->hwnd(), kFullScreenAnimationDuration, AW_BLEND | AW_ACTIVATE); 166} 167 168void FullScreenController::exitFullScreen() 169{ 170 if (!m_private->m_isFullScreen || m_private->m_isExitingFullScreen) 171 return; 172 m_private->m_isFullScreen = false; 173 m_private->m_isExitingFullScreen = true; 174 175 ::AnimateWindow(m_private->m_fullScreenWindow->hwnd(), kFullScreenAnimationDuration, AW_HIDE | AW_BLEND); 176 177 m_private->m_client->fullScreenClientWillExitFullScreen(); 178 m_private->m_client->fullScreenClientSetParentWindow(m_private->m_originalHost); 179 m_private->m_fullScreenWindow = nullptr; 180 181 ::SetWindowPos(m_private->m_client->fullScreenClientWindow(), 0, m_private->m_originalFrame.x(), m_private->m_originalFrame.y(), m_private->m_originalFrame.width(), m_private->m_originalFrame.height(), SWP_NOACTIVATE | SWP_NOZORDER); 182 183 m_private->m_client->fullScreenClientRestoreScrollPosition(); 184 m_private->m_client->fullScreenClientDidExitFullScreen(); 185 m_private->m_client->fullScreenClientForceRepaint(); 186} 187 188void FullScreenController::exitFullScreenRepaintCompleted() 189{ 190 if (!m_private->m_isExitingFullScreen) 191 return; 192 m_private->m_isExitingFullScreen = false; 193 194 ASSERT(m_private->m_backgroundWindow); 195 ::AnimateWindow(m_private->m_backgroundWindow->hwnd(), kFullScreenAnimationDuration, AW_HIDE | AW_BLEND); 196 m_private->m_backgroundWindow = nullptr; 197} 198 199void FullScreenController::repaintCompleted() 200{ 201 if (m_private->m_isEnteringFullScreen) 202 enterFullScreenRepaintCompleted(); 203 else if (m_private->m_isExitingFullScreen) 204 exitFullScreenRepaintCompleted(); 205} 206 207void FullScreenController::close() 208{ 209 if (!m_private->m_isFullScreen) 210 return; 211 m_private->m_isFullScreen = false; 212 213 m_private->m_client->fullScreenClientWillExitFullScreen(); 214 m_private->m_client->fullScreenClientSetParentWindow(m_private->m_originalHost); 215 m_private->m_fullScreenWindow = nullptr; 216 217 m_private->m_client->fullScreenClientDidExitFullScreen(); 218 ::SetWindowPos(m_private->m_client->fullScreenClientWindow(), 0, m_private->m_originalFrame.x(), m_private->m_originalFrame.y(), m_private->m_originalFrame.width(), m_private->m_originalFrame.height(), SWP_NOACTIVATE | SWP_NOZORDER); 219 ::RedrawWindow(m_private->m_client->fullScreenClientWindow(), 0, 0, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN); 220 m_private->m_backgroundWindow = nullptr; 221} 222#endif 223