2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "FullscreenVideoController.h"
32 #include "WebKitDLL.h"
34 #include <ApplicationServices/ApplicationServices.h>
35 #include <WebCore/BitmapInfo.h>
36 #include <WebCore/Chrome.h>
37 #include <WebCore/Font.h>
38 #include <WebCore/FontSelector.h>
39 #include <WebCore/GraphicsContext.h>
40 #include <WebCore/HWndDC.h>
41 #include <WebCore/Page.h>
42 #include <WebCore/PlatformCALayer.h>
43 #include <WebCore/TextRun.h>
44 #include <WebKitSystemInterface/WebKitSystemInterface.h>
46 #include <wtf/OwnPtr.h>
47 #include <wtf/PassOwnPtr.h>
48 #include <wtf/StdLibExtras.h>
51 using namespace WebCore;
53 static const float timerInterval = 0.033;
56 static const int windowHeight = 59;
57 static const int windowWidth = 438;
59 // Margins and button sizes
60 static const int margin = 9;
61 static const int marginTop = 9;
62 static const int buttonSize = 25;
63 static const int buttonMiniSize = 16;
64 static const int volumeSliderWidth = 50;
65 static const int timeSliderWidth = 310;
66 static const int sliderHeight = 8;
67 static const int volumeSliderButtonSize = 10;
68 static const int timeSliderButtonSize = 8;
69 static const int textSize = 11;
70 static const float initialHUDPositionY = 0.9; // Initial Y position of HUD in percentage from top of screen
73 static const int borderRadius = 12;
74 static const int borderThickness = 2;
77 static const unsigned int backgroundColor = 0xA0202020;
78 static const unsigned int borderColor = 0xFFA0A0A0;
79 static const unsigned int sliderGutterColor = 0xFF141414;
80 static const unsigned int sliderButtonColor = 0xFF808080;
81 static const unsigned int textColor = 0xFFFFFFFF;
83 HUDButton::HUDButton(HUDButtonType type, const IntPoint& position)
84 : HUDWidget(IntRect(position, IntSize()))
86 , m_showAltButton(false)
88 const char* buttonResource = 0;
89 const char* buttonResourceAlt = 0;
92 buttonResource = "fsVideoPlay";
93 buttonResourceAlt = "fsVideoPause";
95 case TimeSliderButton:
98 buttonResource = "fsVideoAudioVolumeHigh";
100 case VolumeSliderButton:
102 case VolumeDownButton:
103 buttonResource = "fsVideoAudioVolumeLow";
105 case ExitFullscreenButton:
106 buttonResource = "fsVideoExitFullscreen";
110 if (buttonResource) {
111 m_buttonImage = Image::loadPlatformResource(buttonResource);
112 m_rect.setWidth(m_buttonImage->width());
113 m_rect.setHeight(m_buttonImage->height());
115 if (buttonResourceAlt)
116 m_buttonImageAlt = Image::loadPlatformResource(buttonResourceAlt);
119 void HUDButton::draw(GraphicsContext& context)
121 Image* image = (m_showAltButton && m_buttonImageAlt) ? m_buttonImageAlt.get() : m_buttonImage.get();
122 context.drawImage(image, ColorSpaceDeviceRGB, m_rect.location());
125 HUDSlider::HUDSlider(HUDSliderButtonShape shape, int buttonSize, const IntRect& rect)
127 , m_buttonShape(shape)
128 , m_buttonSize(buttonSize)
129 , m_buttonPosition(0)
130 , m_dragStartOffset(0)
134 void HUDSlider::draw(GraphicsContext& context)
137 IntSize radius(m_rect.height() / 2, m_rect.height() / 2);
138 context.fillRoundedRect(m_rect, radius, radius, radius, radius, Color(sliderGutterColor), ColorSpaceDeviceRGB);
141 context.setStrokeColor(Color(sliderButtonColor), ColorSpaceDeviceRGB);
142 context.setFillColor(Color(sliderButtonColor), ColorSpaceDeviceRGB);
144 if (m_buttonShape == RoundButton) {
145 context.drawEllipse(IntRect(m_rect.location().x() + m_buttonPosition, m_rect.location().y() - (m_buttonSize - m_rect.height()) / 2, m_buttonSize, m_buttonSize));
150 FloatPoint points[4];
151 float half = static_cast<float>(m_buttonSize) / 2;
152 points[0].setX(m_rect.location().x() + m_buttonPosition + half);
153 points[0].setY(m_rect.location().y());
154 points[1].setX(m_rect.location().x() + m_buttonPosition + m_buttonSize);
155 points[1].setY(m_rect.location().y() + half);
156 points[2].setX(m_rect.location().x() + m_buttonPosition + half);
157 points[2].setY(m_rect.location().y() + m_buttonSize);
158 points[3].setX(m_rect.location().x() + m_buttonPosition);
159 points[3].setY(m_rect.location().y() + half);
160 context.drawConvexPolygon(4, points, true);
163 void HUDSlider::drag(const IntPoint& point, bool start)
166 // When we start, we need to snap the slider position to the x position if we clicked the gutter.
167 // But if we click the button, we need to drag relative to where we clicked down. We only need
168 // to check X because we would not even get here unless Y were already inside.
169 int relativeX = point.x() - m_rect.location().x();
170 if (relativeX >= m_buttonPosition && relativeX <= m_buttonPosition + m_buttonSize)
171 m_dragStartOffset = point.x() - m_buttonPosition;
173 m_dragStartOffset = m_rect.location().x() + m_buttonSize / 2;
176 m_buttonPosition = max(0, min(m_rect.width() - m_buttonSize, point.x() - m_dragStartOffset));
179 #if USE(ACCELERATED_COMPOSITING)
180 class FullscreenVideoController::LayerClient : public WebCore::PlatformCALayerClient {
182 LayerClient(FullscreenVideoController* parent) : m_parent(parent) { }
185 virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
186 virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
188 virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
189 virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
190 virtual void platformCALayerPaintContents(GraphicsContext&, const IntRect& inClip) { }
191 virtual bool platformCALayerShowDebugBorders() const { return false; }
192 virtual bool platformCALayerShowRepaintCounter() const { return false; }
193 virtual int platformCALayerIncrementRepaintCount() { return 0; }
195 virtual bool platformCALayerContentsOpaque() const { return false; }
196 virtual bool platformCALayerDrawsContent() const { return false; }
197 virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
198 virtual void platformCALayerDidCreateTiles(const Vector<FloatRect>&) { }
199 virtual float platformCALayerDeviceScaleFactor() { return 1; }
201 FullscreenVideoController* m_parent;
204 void FullscreenVideoController::LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* layer)
206 ASSERT_ARG(layer, layer == m_parent->m_rootChild);
208 HTMLMediaElement* mediaElement = m_parent->m_mediaElement.get();
213 PlatformCALayer* videoLayer = PlatformCALayer::platformCALayer(mediaElement->platformLayer());
214 if (!videoLayer || videoLayer->superlayer() != layer)
217 FloatRect layerBounds = layer->bounds();
219 FloatSize videoSize = mediaElement->player()->naturalSize();
221 if (videoSize.aspectRatio() > layerBounds.size().aspectRatio())
222 scaleFactor = layerBounds.width() / videoSize.width();
224 scaleFactor = layerBounds.height() / videoSize.height();
225 videoSize.scale(scaleFactor);
227 // Calculate the centered position based on the videoBounds and layerBounds:
228 FloatPoint videoPosition;
229 FloatPoint videoOrigin;
230 videoOrigin.setX((layerBounds.width() - videoSize.width()) * 0.5);
231 videoOrigin.setY((layerBounds.height() - videoSize.height()) * 0.5);
232 videoLayer->setFrame(FloatRect(videoOrigin, videoSize));
236 FullscreenVideoController::FullscreenVideoController()
238 , m_playPauseButton(HUDButton::PlayPauseButton, IntPoint((windowWidth - buttonSize) / 2, marginTop))
239 , m_timeSliderButton(HUDButton::TimeSliderButton, IntPoint(0, 0))
240 , m_volumeUpButton(HUDButton::VolumeUpButton, IntPoint(margin + buttonMiniSize + volumeSliderWidth + buttonMiniSize / 2, marginTop + (buttonSize - buttonMiniSize) / 2))
241 , m_volumeSliderButton(HUDButton::VolumeSliderButton, IntPoint(0, 0))
242 , m_volumeDownButton(HUDButton::VolumeDownButton, IntPoint(margin, marginTop + (buttonSize - buttonMiniSize) / 2))
243 , m_exitFullscreenButton(HUDButton::ExitFullscreenButton, IntPoint(windowWidth - 2 * margin - buttonMiniSize, marginTop + (buttonSize - buttonMiniSize) / 2))
244 , m_volumeSlider(HUDSlider::RoundButton, volumeSliderButtonSize, IntRect(IntPoint(margin + buttonMiniSize, marginTop + (buttonSize - buttonMiniSize) / 2 + buttonMiniSize / 2 - sliderHeight / 2), IntSize(volumeSliderWidth, sliderHeight)))
245 , m_timeSlider(HUDSlider::DiamondButton, timeSliderButtonSize, IntRect(IntPoint(windowWidth / 2 - timeSliderWidth / 2, windowHeight - margin - sliderHeight), IntSize(timeSliderWidth, sliderHeight)))
247 , m_movingWindow(false)
248 , m_timer(this, &FullscreenVideoController::timerFired)
249 #if USE(ACCELERATED_COMPOSITING)
250 , m_layerClient(adoptPtr(new LayerClient(this)))
251 , m_rootChild(PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get()))
253 , m_fullscreenWindow(adoptPtr(new MediaPlayerPrivateFullscreenWindow(this)))
257 FullscreenVideoController::~FullscreenVideoController()
259 #if USE(ACCELERATED_COMPOSITING)
260 m_rootChild->setOwner(0);
264 void FullscreenVideoController::setMediaElement(HTMLMediaElement* mediaElement)
266 if (mediaElement == m_mediaElement)
269 m_mediaElement = mediaElement;
270 if (!m_mediaElement) {
271 // Can't do full-screen, just get out
276 void FullscreenVideoController::enterFullscreen()
281 WebView* webView = kit(m_mediaElement->document()->page());
282 HWND parentHwnd = webView ? webView->viewWindow() : 0;
284 m_fullscreenWindow->createWindow(parentHwnd);
285 ::ShowWindow(m_fullscreenWindow->hwnd(), SW_SHOW);
286 #if USE(ACCELERATED_COMPOSITING)
287 m_fullscreenWindow->setRootChildLayer(m_rootChild);
289 PlatformCALayer* videoLayer = PlatformCALayer::platformCALayer(m_mediaElement->platformLayer());
290 m_rootChild->appendSublayer(videoLayer);
291 m_rootChild->setNeedsLayout();
292 m_rootChild->setGeometryFlipped(1);
296 GetClientRect(m_fullscreenWindow->hwnd(), &windowRect);
297 m_fullscreenSize.setWidth(windowRect.right - windowRect.left);
298 m_fullscreenSize.setHeight(windowRect.bottom - windowRect.top);
303 void FullscreenVideoController::exitFullscreen()
305 SetWindowLongPtr(m_hudWindow, 0, 0);
307 if (m_fullscreenWindow)
308 m_fullscreenWindow = nullptr;
310 ASSERT(!IsWindow(m_hudWindow));
313 // We previously ripped the mediaElement's platform layer out
314 // of its orginial layer tree to display it in our fullscreen
315 // window. Now, we need to get the layer back in its original
318 // As a side effect of setting the player to invisible/visible,
319 // the player's layer will be recreated, and will be picked up
320 // the next time the layer tree is synched.
321 m_mediaElement->player()->setVisible(0);
322 m_mediaElement->player()->setVisible(1);
325 bool FullscreenVideoController::canPlay() const
327 return m_mediaElement && m_mediaElement->canPlay();
330 void FullscreenVideoController::play()
333 m_mediaElement->play();
336 void FullscreenVideoController::pause()
339 m_mediaElement->pause();
342 float FullscreenVideoController::volume() const
344 return m_mediaElement ? m_mediaElement->volume() : 0;
347 void FullscreenVideoController::setVolume(float volume)
349 if (m_mediaElement) {
351 m_mediaElement->setVolume(volume, ec);
355 float FullscreenVideoController::currentTime() const
357 return m_mediaElement ? m_mediaElement->currentTime() : 0;
360 void FullscreenVideoController::setCurrentTime(float value)
362 if (m_mediaElement) {
364 m_mediaElement->setCurrentTime(value, ec);
368 float FullscreenVideoController::duration() const
370 return m_mediaElement ? m_mediaElement->duration() : 0;
373 void FullscreenVideoController::beginScrubbing()
376 m_mediaElement->beginScrubbing();
379 void FullscreenVideoController::endScrubbing()
382 m_mediaElement->endScrubbing();
385 LRESULT FullscreenVideoController::fullscreenClientWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
395 onMouseDown(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
398 onMouseMove(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
401 onMouseUp(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
405 return DefWindowProc(wnd, message, wParam, lParam);
408 static const LPCWSTR fullscreenVideeoHUDWindowClassName = L"fullscreenVideeoHUDWindowClass";
410 void FullscreenVideoController::registerHUDWindowClass()
412 static bool haveRegisteredHUDWindowClass;
413 if (haveRegisteredHUDWindowClass)
416 haveRegisteredHUDWindowClass = true;
420 wcex.cbSize = sizeof(WNDCLASSEX);
422 wcex.style = CS_HREDRAW | CS_VREDRAW;
423 wcex.lpfnWndProc = hudWndProc;
426 wcex.hInstance = gInstance;
428 wcex.hCursor = LoadCursor(0, IDC_ARROW);
429 wcex.hbrBackground = 0;
430 wcex.lpszMenuName = 0;
431 wcex.lpszClassName = fullscreenVideeoHUDWindowClassName;
434 RegisterClassEx(&wcex);
437 void FullscreenVideoController::createHUDWindow()
439 m_hudPosition.setX((m_fullscreenSize.width() - windowWidth) / 2);
440 m_hudPosition.setY(m_fullscreenSize.height() * initialHUDPositionY - windowHeight / 2);
442 // Local variable that will hold the returned pixels. No need to cleanup this value. It
443 // will get cleaned up when m_bitmap is destroyed in the dtor
445 BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(windowWidth, windowHeight));
446 m_bitmap = adoptPtr(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
448 // Dirty the window so the HUD draws
449 RECT clearRect = { m_hudPosition.x(), m_hudPosition.y(), m_hudPosition.x() + windowWidth, m_hudPosition.y() + windowHeight };
450 InvalidateRect(m_fullscreenWindow->hwnd(), &clearRect, true);
452 m_playPauseButton.setShowAltButton(!canPlay());
453 m_volumeSlider.setValue(volume());
454 m_timeSlider.setValue(currentTime() / duration());
457 m_timer.startRepeating(timerInterval);
459 registerHUDWindowClass();
461 m_hudWindow = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
462 fullscreenVideeoHUDWindowClassName, 0, WS_POPUP | WS_VISIBLE,
463 m_hudPosition.x(), m_hudPosition.y(), 0, 0, m_fullscreenWindow->hwnd(), 0, gInstance, 0);
464 ASSERT(::IsWindow(m_hudWindow));
465 SetWindowLongPtr(m_hudWindow, 0, reinterpret_cast<LONG_PTR>(this));
470 static String timeToString(float time)
474 int seconds = fabsf(time);
475 int hours = seconds / (60 * 60);
476 int minutes = (seconds / 60) % 60;
481 return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
482 return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
485 return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
488 void FullscreenVideoController::draw()
490 OwnPtr<HDC> bitmapDC = adoptPtr(CreateCompatibleDC(HWndDC(m_hudWindow)));
491 HGDIOBJ oldBitmap = SelectObject(bitmapDC.get(), m_bitmap.get());
493 GraphicsContext context(bitmapDC.get(), true);
497 // Draw the background
498 IntSize outerRadius(borderRadius, borderRadius);
499 IntRect outerRect(0, 0, windowWidth, windowHeight);
500 IntSize innerRadius(borderRadius - borderThickness, borderRadius - borderThickness);
501 IntRect innerRect(borderThickness, borderThickness, windowWidth - borderThickness * 2, windowHeight - borderThickness * 2);
503 context.fillRoundedRect(outerRect, outerRadius, outerRadius, outerRadius, outerRadius, Color(borderColor), ColorSpaceDeviceRGB);
504 context.setCompositeOperation(CompositeCopy);
505 context.fillRoundedRect(innerRect, innerRadius, innerRadius, innerRadius, innerRadius, Color(backgroundColor), ColorSpaceDeviceRGB);
508 m_playPauseButton.draw(context);
509 m_volumeUpButton.draw(context);
510 m_volumeSliderButton.draw(context);
511 m_volumeDownButton.draw(context);
512 m_timeSliderButton.draw(context);
513 m_exitFullscreenButton.draw(context);
514 m_volumeSlider.draw(context);
515 m_timeSlider.draw(context);
517 // Draw the text strings
518 FontDescription desc;
520 NONCLIENTMETRICS metrics;
521 metrics.cbSize = sizeof(metrics);
522 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
524 family.setFamily(metrics.lfSmCaptionFont.lfFaceName);
525 desc.setFamily(family);
527 desc.setComputedSize(textSize);
528 Font font = Font(desc, 0, 0);
533 // The y positioning of these two text strings is tricky because they are so small. They
534 // are currently positioned relative to the center of the slider and then down the font
535 // height / 4 (which is actually half of font height /2), which positions the center of
536 // the text at the center of the slider.
538 s = timeToString(currentTime());
539 int fontHeight = font.fontMetrics().height();
541 context.setFillColor(Color(textColor), ColorSpaceDeviceRGB);
542 context.drawText(font, leftText, IntPoint(windowWidth / 2 - timeSliderWidth / 2 - margin - font.width(leftText), windowHeight - margin - sliderHeight / 2 + fontHeight / 4));
545 s = timeToString(currentTime() - duration());
546 TextRun rightText(s);
547 context.setFillColor(Color(textColor), ColorSpaceDeviceRGB);
548 context.drawText(font, rightText, IntPoint(windowWidth / 2 + timeSliderWidth / 2 + margin, windowHeight - margin - sliderHeight / 2 + fontHeight / 4));
550 // Copy to the window
551 BLENDFUNCTION blendFunction = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
552 SIZE size = { windowWidth, windowHeight };
553 POINT sourcePoint = {0, 0};
554 POINT destPoint = { m_hudPosition.x(), m_hudPosition.y() };
555 BOOL result = UpdateLayeredWindow(m_hudWindow, 0, &destPoint, &size, bitmapDC.get(), &sourcePoint, 0, &blendFunction, ULW_ALPHA);
559 ::SelectObject(bitmapDC.get(), oldBitmap);
562 LRESULT FullscreenVideoController::hudWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
564 LONG_PTR longPtr = GetWindowLongPtr(wnd, 0);
565 FullscreenVideoController* controller = reinterpret_cast<FullscreenVideoController*>(longPtr);
567 return DefWindowProc(wnd, message, wParam, lParam);
571 controller->onChar(wParam);
574 controller->onKeyDown(wParam);
577 controller->onMouseDown(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
580 controller->onMouseMove(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
583 controller->onMouseUp(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
587 return DefWindowProc(wnd, message, wParam, lParam);
590 void FullscreenVideoController::onChar(int c)
592 if (c == VK_ESCAPE) {
594 m_mediaElement->exitFullscreen();
595 } else if (c == VK_SPACE)
599 void FullscreenVideoController::onKeyDown(int virtualKey)
601 if (virtualKey == VK_ESCAPE) {
603 m_mediaElement->exitFullscreen();
607 void FullscreenVideoController::timerFired(Timer<FullscreenVideoController>*)
609 // Update the time slider
610 m_timeSlider.setValue(currentTime() / duration());
614 void FullscreenVideoController::onMouseDown(const IntPoint& point)
616 IntPoint convertedPoint(fullscreenToHUDCoordinates(point));
618 // Don't bother hit testing if we're outside the bounds of the window
619 if (convertedPoint.x() < 0 || convertedPoint.x() >= windowWidth || convertedPoint.y() < 0 || convertedPoint.y() >= windowHeight)
623 m_movingWindow = false;
625 if (m_playPauseButton.hitTest(convertedPoint))
626 m_hitWidget = &m_playPauseButton;
627 else if (m_exitFullscreenButton.hitTest(convertedPoint))
628 m_hitWidget = &m_exitFullscreenButton;
629 else if (m_volumeUpButton.hitTest(convertedPoint))
630 m_hitWidget = &m_volumeUpButton;
631 else if (m_volumeDownButton.hitTest(convertedPoint))
632 m_hitWidget = &m_volumeDownButton;
633 else if (m_volumeSlider.hitTest(convertedPoint)) {
634 m_hitWidget = &m_volumeSlider;
635 m_volumeSlider.drag(convertedPoint, true);
636 setVolume(m_volumeSlider.value());
637 } else if (m_timeSlider.hitTest(convertedPoint)) {
638 m_hitWidget = &m_timeSlider;
639 m_timeSlider.drag(convertedPoint, true);
641 setCurrentTime(m_timeSlider.value() * duration());
644 // If we did not pick any of our widgets we are starting a window move
646 m_moveOffset = convertedPoint;
647 m_movingWindow = true;
653 void FullscreenVideoController::onMouseMove(const IntPoint& point)
655 IntPoint convertedPoint(fullscreenToHUDCoordinates(point));
658 m_hitWidget->drag(convertedPoint, false);
659 if (m_hitWidget == &m_volumeSlider)
660 setVolume(m_volumeSlider.value());
661 else if (m_hitWidget == &m_timeSlider)
662 setCurrentTime(m_timeSlider.value() * duration());
664 } else if (m_movingWindow)
665 m_hudPosition.move(convertedPoint.x() - m_moveOffset.x(), convertedPoint.y() - m_moveOffset.y());
668 void FullscreenVideoController::onMouseUp(const IntPoint& point)
670 IntPoint convertedPoint(fullscreenToHUDCoordinates(point));
671 m_movingWindow = false;
674 if (m_hitWidget == &m_playPauseButton && m_playPauseButton.hitTest(convertedPoint))
676 else if (m_hitWidget == &m_volumeUpButton && m_volumeUpButton.hitTest(convertedPoint)) {
678 m_volumeSlider.setValue(1);
679 } else if (m_hitWidget == &m_volumeDownButton && m_volumeDownButton.hitTest(convertedPoint)) {
681 m_volumeSlider.setValue(0);
682 } else if (m_hitWidget == &m_timeSlider)
684 else if (m_hitWidget == &m_exitFullscreenButton && m_exitFullscreenButton.hitTest(convertedPoint)) {
687 m_mediaElement->exitFullscreen();
696 void FullscreenVideoController::togglePlay()
703 m_playPauseButton.setShowAltButton(!canPlay());
705 // Run a timer while the video is playing so we can keep the time
706 // slider and time values up to date.
708 m_timer.startRepeating(timerInterval);