blob: cc7ad3ec310baff9f2d5313ea37ebb667c79d4eb [file] [log] [blame]
/*
* 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 <wtf/RefPtr.h>
namespace WebCore {
static const int kFullScreenAnimationDuration = 500; // milliseconds
class FullScreenController::Private : public MediaPlayerPrivateFullscreenClient {
WTF_MAKE_FAST_ALLOCATED;
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() = default;
virtual LRESULT fullscreenClientWndProc(HWND, UINT, WPARAM, LPARAM);
FullScreenController* m_controller;
FullScreenControllerClient* m_client;
std::unique_ptr<MediaPlayerPrivateFullscreenWindow> m_fullScreenWindow;
std::unique_ptr<MediaPlayerPrivateFullscreenWindow> 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(makeUnique<Private>(this, client))
{
ASSERT_ARG(client, client);
}
FullScreenController::~FullScreenController() = default;
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<LPPOINT>(&originalFrame), 2);
m_private->m_originalFrame = originalFrame;
ASSERT(!m_private->m_backgroundWindow);
m_private->m_backgroundWindow = makeUnique<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 = makeUnique<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;
}
} // namespace WebCore
#endif