/* * Copyright (C) 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. * Copyright (C) Research In Motion Limited 2009. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if ENABLE(FULLSCREEN_API) #include "FullScreenController.h" #include "Element.h" #include "FullScreenControllerClient.h" #include "IntRect.h" #include "MediaPlayerPrivateFullscreenWindow.h" #include "Timer.h" #include "WebCoreInstanceHandle.h" #include using namespace WebCore; static const int kFullScreenAnimationDuration = 500; // milliseconds class FullScreenController::Private : public MediaPlayerPrivateFullscreenClient { public: Private(FullScreenController* controller, FullScreenControllerClient* client) : m_controller(controller) , m_client(client) , m_originalHost(0) , m_isFullScreen(false) , m_isEnteringFullScreen(false) , m_isExitingFullScreen(false) { } virtual ~Private() { } virtual LRESULT fullscreenClientWndProc(HWND, UINT, WPARAM, LPARAM); FullScreenController* m_controller; FullScreenControllerClient* m_client; OwnPtr m_fullScreenWindow; OwnPtr m_backgroundWindow; IntRect m_fullScreenFrame; IntRect m_originalFrame; HWND m_originalHost; bool m_isFullScreen; bool m_isEnteringFullScreen; bool m_isExitingFullScreen; }; LRESULT FullScreenController::Private::fullscreenClientWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0; switch (msg) { case WM_MOVE: m_fullScreenFrame.setX(LOWORD(lParam)); m_fullScreenFrame.setY(HIWORD(lParam)); break; case WM_SIZE: m_fullScreenFrame.setWidth(LOWORD(lParam)); m_fullScreenFrame.setHeight(HIWORD(lParam)); if (m_client->fullScreenClientWindow()) ::SetWindowPos(m_client->fullScreenClientWindow(), 0, 0, 0, m_fullScreenFrame.width(), m_fullScreenFrame.height(), SWP_NOREPOSITION | SWP_NOMOVE); break; case WM_ACTIVATE: // Because m_fullScreenWindow is a topmost window, we need to exit full screen explicitly when it's deactivated. if (!wParam && m_fullScreenWindow && (hwnd == m_fullScreenWindow->hwnd())) m_controller->exitFullScreen(); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) { m_controller->exitFullScreen(); break; } FALLTHROUGH; default: lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); } return lResult; } FullScreenController::FullScreenController(FullScreenControllerClient* client) : m_private(adoptPtr(new FullScreenController::Private(this, client))) { ASSERT_ARG(client, client); } FullScreenController::~FullScreenController() { } bool FullScreenController::isFullScreen() const { return m_private->m_isFullScreen; } void FullScreenController::enterFullScreen() { if (m_private->m_isFullScreen || m_private->m_isEnteringFullScreen) return; m_private->m_isFullScreen = true; m_private->m_isEnteringFullScreen = true; m_private->m_client->fullScreenClientSaveScrollPosition(); m_private->m_originalHost = m_private->m_client->fullScreenClientParentWindow(); RECT originalFrame = {0, 0, 0, 0}; ::GetClientRect(m_private->m_client->fullScreenClientWindow(), &originalFrame); ::MapWindowPoints(m_private->m_client->fullScreenClientWindow(), m_private->m_originalHost, reinterpret_cast(&originalFrame), 2); m_private->m_originalFrame = originalFrame; ASSERT(!m_private->m_backgroundWindow); m_private->m_backgroundWindow = adoptPtr(new MediaPlayerPrivateFullscreenWindow(m_private.get())); m_private->m_backgroundWindow->createWindow(0); ::AnimateWindow(m_private->m_backgroundWindow->hwnd(), kFullScreenAnimationDuration, AW_BLEND | AW_ACTIVATE); m_private->m_client->fullScreenClientWillEnterFullScreen(); ASSERT(!m_private->m_fullScreenWindow); m_private->m_fullScreenWindow = adoptPtr(new MediaPlayerPrivateFullscreenWindow(m_private.get())); ASSERT(m_private->m_fullScreenWindow); m_private->m_fullScreenWindow->createWindow(0); m_private->m_client->fullScreenClientSetParentWindow(m_private->m_fullScreenWindow->hwnd()); IntRect viewFrame(IntPoint(), m_private->m_fullScreenFrame.size()); ::SetWindowPos(m_private->m_fullScreenWindow->hwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); ::SetWindowPos(m_private->m_client->fullScreenClientWindow(), HWND_TOP, 0, 0, viewFrame.width(), viewFrame.height(), SWP_NOACTIVATE); m_private->m_client->fullScreenClientDidEnterFullScreen(); m_private->m_client->fullScreenClientForceRepaint(); } void FullScreenController::enterFullScreenRepaintCompleted() { if (!m_private->m_isEnteringFullScreen) return; m_private->m_isEnteringFullScreen = false; // Normally, when the background fullscreen window is animated in, the Windows taskbar will be hidden, but this doesn't always work for some reason. // 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. ::SetWindowPos(m_private->m_fullScreenWindow->hwnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); ::AnimateWindow(m_private->m_fullScreenWindow->hwnd(), kFullScreenAnimationDuration, AW_BLEND | AW_ACTIVATE); } void FullScreenController::exitFullScreen() { if (!m_private->m_isFullScreen || m_private->m_isExitingFullScreen) return; m_private->m_isFullScreen = false; m_private->m_isExitingFullScreen = true; ::AnimateWindow(m_private->m_fullScreenWindow->hwnd(), kFullScreenAnimationDuration, AW_HIDE | AW_BLEND); m_private->m_client->fullScreenClientWillExitFullScreen(); m_private->m_client->fullScreenClientSetParentWindow(m_private->m_originalHost); m_private->m_fullScreenWindow = nullptr; ::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); m_private->m_client->fullScreenClientRestoreScrollPosition(); m_private->m_client->fullScreenClientDidExitFullScreen(); m_private->m_client->fullScreenClientForceRepaint(); } void FullScreenController::exitFullScreenRepaintCompleted() { if (!m_private->m_isExitingFullScreen) return; m_private->m_isExitingFullScreen = false; ASSERT(m_private->m_backgroundWindow); ::AnimateWindow(m_private->m_backgroundWindow->hwnd(), kFullScreenAnimationDuration, AW_HIDE | AW_BLEND); m_private->m_backgroundWindow = nullptr; } void FullScreenController::repaintCompleted() { if (m_private->m_isEnteringFullScreen) enterFullScreenRepaintCompleted(); else if (m_private->m_isExitingFullScreen) exitFullScreenRepaintCompleted(); } void FullScreenController::close() { if (!m_private->m_isFullScreen) return; m_private->m_isFullScreen = false; m_private->m_client->fullScreenClientWillExitFullScreen(); m_private->m_client->fullScreenClientSetParentWindow(m_private->m_originalHost); m_private->m_fullScreenWindow = nullptr; m_private->m_client->fullScreenClientDidExitFullScreen(); ::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); ::RedrawWindow(m_private->m_client->fullScreenClientWindow(), 0, 0, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN); m_private->m_backgroundWindow = nullptr; } #endif