blob: c52655f71d88c0de4a8fcb5a63c6f4cdcf0b68cf [file] [log] [blame]
/*
* Copyright (C) 2010, 2013 Apple Inc. 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.
*/
#if ENABLE(VIDEO) && !USE(GSTREAMER) && !USE(MEDIA_FOUNDATION)
#include "FullscreenVideoController.h"
#include "WebKitDLL.h"
#include "WebView.h"
#include <WebCore/BitmapInfo.h>
#include <WebCore/Chrome.h>
#include <WebCore/FloatRoundedRect.h>
#include <WebCore/FontCascade.h>
#include <WebCore/FontSelector.h>
#include <WebCore/GraphicsContext.h>
#include <WebCore/GraphicsContextWin.h>
#include <WebCore/HWndDC.h>
#include <WebCore/Page.h>
#include <WebCore/TextRun.h>
#include <windowsx.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/StringConcatenateNumbers.h>
#if USE(CA)
#include <WebCore/PlatformCALayerClient.h>
#include <WebCore/PlatformCALayerWin.h>
#endif
using namespace WebCore;
static const Seconds timerInterval { 33_ms };
// HUD Size
static const int windowHeight = 59;
static const int windowWidth = 438;
// Margins and button sizes
static const int margin = 9;
static const int marginTop = 9;
static const int buttonSize = 25;
static const int buttonMiniSize = 16;
static const int volumeSliderWidth = 50;
static const int timeSliderWidth = 310;
static const int sliderHeight = 8;
static const int volumeSliderButtonSize = 10;
static const int timeSliderButtonSize = 8;
static const int textSize = 11;
static const float initialHUDPositionY = 0.9; // Initial Y position of HUD in percentage from top of screen
// Background values
static const int borderRadius = 12;
static const int borderThickness = 2;
// Colors
static constexpr auto backgroundColor = SRGBA<uint8_t> { 32, 32, 32, 160 };
static constexpr auto borderColor = SRGBA<uint8_t> { 160, 160, 160 };
static constexpr auto sliderGutterColor = SRGBA<uint8_t> { 20, 20, 20 };
static constexpr auto sliderButtonColor = SRGBA<uint8_t> { 128, 128, 128 };
static constexpr auto textColor = Color::white;
HUDButton::HUDButton(HUDButtonType type, const IntPoint& position)
: HUDWidget(IntRect(position, IntSize()))
, m_type(type)
, m_showAltButton(false)
{
const char* buttonResource = 0;
const char* buttonResourceAlt = 0;
switch (m_type) {
case PlayPauseButton:
buttonResource = "fsVideoPlay";
buttonResourceAlt = "fsVideoPause";
break;
case TimeSliderButton:
break;
case VolumeUpButton:
buttonResource = "fsVideoAudioVolumeHigh";
break;
case VolumeSliderButton:
break;
case VolumeDownButton:
buttonResource = "fsVideoAudioVolumeLow";
break;
case ExitFullscreenButton:
buttonResource = "fsVideoExitFullscreen";
break;
}
if (buttonResource) {
m_buttonImage = Image::loadPlatformResource(buttonResource);
m_rect.setWidth(m_buttonImage->width());
m_rect.setHeight(m_buttonImage->height());
}
if (buttonResourceAlt)
m_buttonImageAlt = Image::loadPlatformResource(buttonResourceAlt);
}
void HUDButton::draw(GraphicsContext& context)
{
Image* image = (m_showAltButton && m_buttonImageAlt) ? m_buttonImageAlt.get() : m_buttonImage.get();
context.drawImage(*image, m_rect.location());
}
HUDSlider::HUDSlider(HUDSliderButtonShape shape, int buttonSize, const IntRect& rect)
: HUDWidget(rect)
, m_buttonShape(shape)
, m_buttonSize(buttonSize)
, m_buttonPosition(0)
, m_dragStartOffset(0)
{
}
void HUDSlider::draw(GraphicsContext& context)
{
// Draw gutter
IntSize radius(m_rect.height() / 2, m_rect.height() / 2);
context.fillRoundedRect(FloatRoundedRect(m_rect, radius, radius, radius, radius), Color(sliderGutterColor));
// Draw button
context.setStrokeColor(Color(sliderButtonColor));
context.setFillColor(Color(sliderButtonColor));
if (m_buttonShape == RoundButton) {
context.drawEllipse(IntRect(m_rect.location().x() + m_buttonPosition, m_rect.location().y() - (m_buttonSize - m_rect.height()) / 2, m_buttonSize, m_buttonSize));
return;
}
// Draw a diamond
float half = static_cast<float>(m_buttonSize) / 2;
Vector<FloatPoint> points = {
FloatPoint(m_rect.location().x() + m_buttonPosition + half, m_rect.location().y()),
FloatPoint(m_rect.location().x() + m_buttonPosition + m_buttonSize, m_rect.location().y() + half),
FloatPoint(m_rect.location().x() + m_buttonPosition + half, m_rect.location().y() + m_buttonSize),
FloatPoint(m_rect.location().x() + m_buttonPosition, m_rect.location().y() + half)
};
context.drawPath(Path::polygonPathFromPoints(points));
}
void HUDSlider::drag(const IntPoint& point, bool start)
{
if (start) {
// When we start, we need to snap the slider position to the x position if we clicked the gutter.
// But if we click the button, we need to drag relative to where we clicked down. We only need
// to check X because we would not even get here unless Y were already inside.
int relativeX = point.x() - m_rect.location().x();
if (relativeX >= m_buttonPosition && relativeX <= m_buttonPosition + m_buttonSize)
m_dragStartOffset = point.x() - m_buttonPosition;
else
m_dragStartOffset = m_rect.location().x() + m_buttonSize / 2;
}
m_buttonPosition = std::max(0, std::min(m_rect.width() - m_buttonSize, point.x() - m_dragStartOffset));
}
#if USE(CA)
class FullscreenVideoController::LayerClient : public WebCore::PlatformCALayerClient {
WTF_MAKE_FAST_ALLOCATED;
public:
LayerClient(FullscreenVideoController* parent) : m_parent(parent) { }
private:
virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
virtual void platformCALayerAnimationStarted(MonotonicTime beginTime) { }
virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesOrientation::BottomUp; }
virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintBehavior) { }
virtual bool platformCALayerShowDebugBorders() const { return false; }
virtual bool platformCALayerShowRepaintCounter(PlatformCALayer*) const { return false; }
virtual int platformCALayerIncrementRepaintCount(PlatformCALayer*) { return 0; }
virtual bool platformCALayerContentsOpaque() const { return false; }
virtual bool platformCALayerDrawsContent() const { return false; }
virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
virtual void platformCALayerDidCreateTiles(const Vector<FloatRect>&) { }
float platformCALayerDeviceScaleFactor() const override { return 1; }
FullscreenVideoController* m_parent;
};
void FullscreenVideoController::LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* layer)
{
ASSERT_ARG(layer, layer == m_parent->m_rootChild);
HTMLVideoElement* videoElement = m_parent->m_videoElement.get();
if (!videoElement)
return;
auto videoLayer = PlatformCALayer::platformCALayerForLayer(videoElement->platformLayer());
if (!videoLayer || videoLayer->superlayer() != layer)
return;
FloatRect layerBounds = layer->bounds();
FloatSize videoSize = videoElement->player()->naturalSize();
float scaleFactor;
if (videoSize.aspectRatio() > layerBounds.size().aspectRatio())
scaleFactor = layerBounds.width() / videoSize.width();
else
scaleFactor = layerBounds.height() / videoSize.height();
videoSize.scale(scaleFactor);
// Calculate the centered position based on the videoBounds and layerBounds:
FloatPoint videoPosition;
FloatPoint videoOrigin;
videoOrigin.setX((layerBounds.width() - videoSize.width()) * 0.5);
videoOrigin.setY((layerBounds.height() - videoSize.height()) * 0.5);
videoLayer->setPosition(videoOrigin);
videoLayer->setBounds(FloatRect(FloatPoint(), videoSize));
}
#endif
FullscreenVideoController::FullscreenVideoController()
: m_hudWindow(0)
, m_playPauseButton(HUDButton::PlayPauseButton, IntPoint((windowWidth - buttonSize) / 2, marginTop))
, m_timeSliderButton(HUDButton::TimeSliderButton, IntPoint(0, 0))
, m_volumeUpButton(HUDButton::VolumeUpButton, IntPoint(margin + buttonMiniSize + volumeSliderWidth + buttonMiniSize / 2, marginTop + (buttonSize - buttonMiniSize) / 2))
, m_volumeSliderButton(HUDButton::VolumeSliderButton, IntPoint(0, 0))
, m_volumeDownButton(HUDButton::VolumeDownButton, IntPoint(margin, marginTop + (buttonSize - buttonMiniSize) / 2))
, m_exitFullscreenButton(HUDButton::ExitFullscreenButton, IntPoint(windowWidth - 2 * margin - buttonMiniSize, marginTop + (buttonSize - buttonMiniSize) / 2))
, m_volumeSlider(HUDSlider::RoundButton, volumeSliderButtonSize, IntRect(IntPoint(margin + buttonMiniSize, marginTop + (buttonSize - buttonMiniSize) / 2 + buttonMiniSize / 2 - sliderHeight / 2), IntSize(volumeSliderWidth, sliderHeight)))
, m_timeSlider(HUDSlider::DiamondButton, timeSliderButtonSize, IntRect(IntPoint(windowWidth / 2 - timeSliderWidth / 2, windowHeight - margin - sliderHeight), IntSize(timeSliderWidth, sliderHeight)))
, m_hitWidget(0)
, m_movingWindow(false)
, m_timer(*this, &FullscreenVideoController::timerFired)
#if USE(CA)
, m_layerClient(makeUnique<LayerClient>(this))
, m_rootChild(PlatformCALayerWin::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get()))
#endif
#if ENABLE(FULLSCREEN_API)
, m_fullscreenWindow(makeUnique<MediaPlayerPrivateFullscreenWindow>(static_cast<MediaPlayerPrivateFullscreenClient*>(this)))
#endif
{
}
FullscreenVideoController::~FullscreenVideoController()
{
#if USE(CA)
m_rootChild->setOwner(0);
#endif
}
void FullscreenVideoController::setVideoElement(HTMLVideoElement* videoElement)
{
if (videoElement == m_videoElement)
return;
m_videoElement = videoElement;
if (!m_videoElement) {
// Can't do full-screen, just get out
exitFullscreen();
}
}
void FullscreenVideoController::enterFullscreen()
{
#if ENABLE(FULLSCREEN_API)
if (!m_videoElement)
return;
WebView* webView = kit(m_videoElement->document().page());
HWND parentHwnd = webView ? webView->viewWindow() : 0;
m_fullscreenWindow->createWindow(parentHwnd);
::ShowWindow(m_fullscreenWindow->hwnd(), SW_SHOW);
#if USE(CA)
m_fullscreenWindow->setRootChildLayer(*m_rootChild);
auto videoLayer = PlatformCALayer::platformCALayerForLayer(m_videoElement->platformLayer());
ASSERT(videoLayer);
m_rootChild->appendSublayer(*videoLayer);
m_rootChild->setNeedsLayout();
m_rootChild->setGeometryFlipped(1);
#endif
RECT windowRect;
GetClientRect(m_fullscreenWindow->hwnd(), &windowRect);
m_fullscreenSize.setWidth(windowRect.right - windowRect.left);
m_fullscreenSize.setHeight(windowRect.bottom - windowRect.top);
createHUDWindow();
#endif
}
void FullscreenVideoController::exitFullscreen()
{
SetWindowLongPtr(m_hudWindow, 0, 0);
#if ENABLE(FULLSCREEN_API)
m_fullscreenWindow = nullptr;
#endif
ASSERT(!IsWindow(m_hudWindow));
m_hudWindow = 0;
// We previously ripped the videoElement's platform layer out
// of its orginial layer tree to display it in our fullscreen
// window. Now, we need to get the layer back in its original
// tree.
//
// As a side effect of setting the player to invisible/visible,
// the player's layer will be recreated, and will be picked up
// the next time the layer tree is synched.
m_videoElement->player()->setPageIsVisible(0);
m_videoElement->player()->setPageIsVisible(1);
}
bool FullscreenVideoController::canPlay() const
{
return m_videoElement && m_videoElement->canPlay();
}
void FullscreenVideoController::play()
{
if (m_videoElement)
m_videoElement->play();
}
void FullscreenVideoController::pause()
{
if (m_videoElement)
m_videoElement->pause();
}
float FullscreenVideoController::volume() const
{
return m_videoElement ? m_videoElement->volume() : 0;
}
void FullscreenVideoController::setVolume(float volume)
{
if (m_videoElement)
m_videoElement->setVolume(volume);
}
float FullscreenVideoController::currentTime() const
{
return m_videoElement ? m_videoElement->currentTime() : 0;
}
void FullscreenVideoController::setCurrentTime(float value)
{
if (m_videoElement)
m_videoElement->setCurrentTime(value);
}
float FullscreenVideoController::duration() const
{
return m_videoElement ? m_videoElement->duration() : 0;
}
void FullscreenVideoController::beginScrubbing()
{
if (m_videoElement)
m_videoElement->beginScrubbing();
}
void FullscreenVideoController::endScrubbing()
{
if (m_videoElement)
m_videoElement->endScrubbing();
}
LRESULT FullscreenVideoController::fullscreenClientWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CHAR:
onChar(wParam);
break;
case WM_KEYDOWN:
onKeyDown(wParam);
break;
case WM_LBUTTONDOWN:
onMouseDown(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
case WM_MOUSEMOVE:
onMouseMove(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
case WM_LBUTTONUP:
onMouseUp(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
}
return DefWindowProc(wnd, message, wParam, lParam);
}
static const LPCWSTR fullscreenVideeoHUDWindowClassName = L"fullscreenVideeoHUDWindowClass";
void FullscreenVideoController::registerHUDWindowClass()
{
static bool haveRegisteredHUDWindowClass;
if (haveRegisteredHUDWindowClass)
return;
haveRegisteredHUDWindowClass = true;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = hudWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(FullscreenVideoController*);
wcex.hInstance = gInstance;
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = fullscreenVideeoHUDWindowClassName;
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
}
void FullscreenVideoController::createHUDWindow()
{
#if ENABLE(FULLSCREEN_API)
m_hudPosition.setX((m_fullscreenSize.width() - windowWidth) / 2);
m_hudPosition.setY(m_fullscreenSize.height() * initialHUDPositionY - windowHeight / 2);
// Local variable that will hold the returned pixels. No need to cleanup this value. It
// will get cleaned up when m_bitmap is destroyed in the dtor
void* pixels;
BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(windowWidth, windowHeight));
m_bitmap = adoptGDIObject(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
// Dirty the window so the HUD draws
RECT clearRect = { m_hudPosition.x(), m_hudPosition.y(), m_hudPosition.x() + windowWidth, m_hudPosition.y() + windowHeight };
InvalidateRect(m_fullscreenWindow->hwnd(), &clearRect, true);
m_playPauseButton.setShowAltButton(!canPlay());
m_volumeSlider.setValue(volume());
m_timeSlider.setValue(currentTime() / duration());
if (!canPlay())
m_timer.startRepeating(timerInterval);
registerHUDWindowClass();
m_hudWindow = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
fullscreenVideeoHUDWindowClassName, 0, WS_POPUP | WS_VISIBLE,
m_hudPosition.x(), m_hudPosition.y(), 0, 0, m_fullscreenWindow->hwnd(), 0, gInstance, 0);
ASSERT(::IsWindow(m_hudWindow));
SetWindowLongPtr(m_hudWindow, 0, reinterpret_cast<LONG_PTR>(this));
draw();
#endif
}
static String timeToString(float time)
{
if (!std::isfinite(time))
time = 0;
int seconds = fabsf(time);
int hours = seconds / (60 * 60);
int minutes = (seconds / 60) % 60;
seconds %= 60;
if (hours)
return makeString((time < 0 ? "-" : ""), hours, ':', pad('0', 2, minutes), ':', pad('0', 2, seconds));
return makeString((time < 0 ? "-" : ""), pad('0', 2, minutes), ':', pad('0', 2, seconds));
}
void FullscreenVideoController::draw()
{
auto bitmapDC = adoptGDIObject(::CreateCompatibleDC(HWndDC(m_hudWindow)));
HGDIOBJ oldBitmap = SelectObject(bitmapDC.get(), m_bitmap.get());
GraphicsContextWin context(bitmapDC.get(), true);
context.save();
// Draw the background
IntSize outerRadius(borderRadius, borderRadius);
IntRect outerRect(0, 0, windowWidth, windowHeight);
IntSize innerRadius(borderRadius - borderThickness, borderRadius - borderThickness);
IntRect innerRect(borderThickness, borderThickness, windowWidth - borderThickness * 2, windowHeight - borderThickness * 2);
context.fillRoundedRect(FloatRoundedRect(outerRect, outerRadius, outerRadius, outerRadius, outerRadius), Color(borderColor));
context.setCompositeOperation(CompositeOperator::Copy);
context.fillRoundedRect(FloatRoundedRect(innerRect, innerRadius, innerRadius, innerRadius, innerRadius), Color(backgroundColor));
// Draw the widgets
m_playPauseButton.draw(context);
m_volumeUpButton.draw(context);
m_volumeSliderButton.draw(context);
m_volumeDownButton.draw(context);
m_timeSliderButton.draw(context);
m_exitFullscreenButton.draw(context);
m_volumeSlider.draw(context);
m_timeSlider.draw(context);
// Draw the text strings
FontCascadeDescription desc;
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(metrics);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
desc.setOneFamily(metrics.lfSmCaptionFont.lfFaceName);
desc.setComputedSize(textSize);
FontCascade font = FontCascade(WTFMove(desc), 0, 0);
font.update();
String s;
// The y positioning of these two text strings is tricky because they are so small. They
// are currently positioned relative to the center of the slider and then down the font
// height / 4 (which is actually half of font height /2), which positions the center of
// the text at the center of the slider.
// Left string
s = timeToString(currentTime());
int fontHeight = font.metricsOfPrimaryFont().height();
TextRun leftText(s);
context.setFillColor(Color(textColor));
context.drawText(font, leftText, IntPoint(windowWidth / 2 - timeSliderWidth / 2 - margin - font.width(leftText), windowHeight - margin - sliderHeight / 2 + fontHeight / 4));
// Right string
s = timeToString(currentTime() - duration());
TextRun rightText(s);
context.setFillColor(Color(textColor));
context.drawText(font, rightText, IntPoint(windowWidth / 2 + timeSliderWidth / 2 + margin, windowHeight - margin - sliderHeight / 2 + fontHeight / 4));
// Copy to the window
BLENDFUNCTION blendFunction = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
SIZE size = { windowWidth, windowHeight };
POINT sourcePoint = {0, 0};
POINT destPoint = { m_hudPosition.x(), m_hudPosition.y() };
BOOL result = UpdateLayeredWindow(m_hudWindow, 0, &destPoint, &size, bitmapDC.get(), &sourcePoint, 0, &blendFunction, ULW_ALPHA);
context.restore();
::SelectObject(bitmapDC.get(), oldBitmap);
}
LRESULT FullscreenVideoController::hudWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LONG_PTR longPtr = GetWindowLongPtr(wnd, 0);
FullscreenVideoController* controller = reinterpret_cast<FullscreenVideoController*>(longPtr);
if (!controller)
return DefWindowProc(wnd, message, wParam, lParam);
switch (message) {
case WM_CHAR:
controller->onChar(wParam);
break;
case WM_KEYDOWN:
controller->onKeyDown(wParam);
break;
case WM_LBUTTONDOWN:
controller->onMouseDown(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
case WM_MOUSEMOVE:
controller->onMouseMove(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
case WM_LBUTTONUP:
controller->onMouseUp(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
break;
}
return DefWindowProc(wnd, message, wParam, lParam);
}
void FullscreenVideoController::onChar(int c)
{
if (c == VK_ESCAPE) {
if (m_videoElement)
m_videoElement->exitFullscreen();
} else if (c == VK_SPACE)
togglePlay();
}
void FullscreenVideoController::onKeyDown(int virtualKey)
{
if (virtualKey == VK_ESCAPE) {
if (m_videoElement)
m_videoElement->exitFullscreen();
}
}
void FullscreenVideoController::timerFired()
{
// Update the time slider
m_timeSlider.setValue(currentTime() / duration());
draw();
}
void FullscreenVideoController::onMouseDown(const IntPoint& point)
{
IntPoint convertedPoint(fullscreenToHUDCoordinates(point));
// Don't bother hit testing if we're outside the bounds of the window
if (convertedPoint.x() < 0 || convertedPoint.x() >= windowWidth || convertedPoint.y() < 0 || convertedPoint.y() >= windowHeight)
return;
m_hitWidget = 0;
m_movingWindow = false;
if (m_playPauseButton.hitTest(convertedPoint))
m_hitWidget = &m_playPauseButton;
else if (m_exitFullscreenButton.hitTest(convertedPoint))
m_hitWidget = &m_exitFullscreenButton;
else if (m_volumeUpButton.hitTest(convertedPoint))
m_hitWidget = &m_volumeUpButton;
else if (m_volumeDownButton.hitTest(convertedPoint))
m_hitWidget = &m_volumeDownButton;
else if (m_volumeSlider.hitTest(convertedPoint)) {
m_hitWidget = &m_volumeSlider;
m_volumeSlider.drag(convertedPoint, true);
setVolume(m_volumeSlider.value());
} else if (m_timeSlider.hitTest(convertedPoint)) {
m_hitWidget = &m_timeSlider;
m_timeSlider.drag(convertedPoint, true);
beginScrubbing();
setCurrentTime(m_timeSlider.value() * duration());
}
// If we did not pick any of our widgets we are starting a window move
if (!m_hitWidget) {
m_moveOffset = convertedPoint;
m_movingWindow = true;
}
draw();
}
void FullscreenVideoController::onMouseMove(const IntPoint& point)
{
IntPoint convertedPoint(fullscreenToHUDCoordinates(point));
if (m_hitWidget) {
m_hitWidget->drag(convertedPoint, false);
if (m_hitWidget == &m_volumeSlider)
setVolume(m_volumeSlider.value());
else if (m_hitWidget == &m_timeSlider)
setCurrentTime(m_timeSlider.value() * duration());
draw();
} else if (m_movingWindow)
m_hudPosition.move(convertedPoint.x() - m_moveOffset.x(), convertedPoint.y() - m_moveOffset.y());
}
void FullscreenVideoController::onMouseUp(const IntPoint& point)
{
IntPoint convertedPoint(fullscreenToHUDCoordinates(point));
m_movingWindow = false;
if (m_hitWidget) {
if (m_hitWidget == &m_playPauseButton && m_playPauseButton.hitTest(convertedPoint))
togglePlay();
else if (m_hitWidget == &m_volumeUpButton && m_volumeUpButton.hitTest(convertedPoint)) {
setVolume(1);
m_volumeSlider.setValue(1);
} else if (m_hitWidget == &m_volumeDownButton && m_volumeDownButton.hitTest(convertedPoint)) {
setVolume(0);
m_volumeSlider.setValue(0);
} else if (m_hitWidget == &m_timeSlider)
endScrubbing();
else if (m_hitWidget == &m_exitFullscreenButton && m_exitFullscreenButton.hitTest(convertedPoint)) {
m_hitWidget = 0;
if (m_videoElement)
m_videoElement->exitFullscreen();
return;
}
}
m_hitWidget = 0;
draw();
}
void FullscreenVideoController::togglePlay()
{
if (canPlay())
play();
else
pause();
m_playPauseButton.setShowAltButton(!canPlay());
// Run a timer while the video is playing so we can keep the time
// slider and time values up to date.
if (!canPlay())
m_timer.startRepeating(timerInterval);
else
m_timer.stop();
draw();
}
#endif