Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      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.
     12  *
     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.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if ENABLE(VIDEO)
     29 
     30 #include "FullscreenVideoController.h"
     31 
     32 #include "WebKitDLL.h"
     33 #include <ApplicationServices/ApplicationServices.h>
     34 #include <WebCore/BitmapInfo.h>
     35 #include <WebCore/Font.h>
     36 #include <WebCore/FontSelector.h>
     37 #include <WebCore/GraphicsContext.h>
     38 #include <WebCore/TextRun.h>
     39 #include <WebKitSystemInterface/WebKitSystemInterface.h>
     40 #include <windowsx.h>
     41 #include <wtf/StdLibExtras.h>
     42 
     43 using namespace std;
     44 using namespace WebCore;
     45 
     46 static const float timerInterval = 0.033;
     47 
     48 // HUD Size
     49 static const int windowHeight = 59;
     50 static const int windowWidth = 438;
     51 
     52 // Margins and button sizes
     53 static const int margin = 9;
     54 static const int marginTop = 9;
     55 static const int buttonSize = 25;
     56 static const int buttonMiniSize = 16;
     57 static const int volumeSliderWidth = 50;
     58 static const int timeSliderWidth = 310;
     59 static const int sliderHeight = 8;
     60 static const int volumeSliderButtonSize = 10;
     61 static const int timeSliderButtonSize = 8;
     62 static const int textSize = 11;
     63 static const float initialHUDPositionY = 0.9; // Initial Y position of HUD in percentage from top of screen
     64 
     65 // Background values
     66 static const int borderRadius = 12;
     67 static const int borderThickness = 2;
     68 
     69 // Colors
     70 static const unsigned int backgroundColor = 0xA0202020;
     71 static const unsigned int borderColor = 0xFFA0A0A0;
     72 static const unsigned int sliderGutterColor = 0xFF141414;
     73 static const unsigned int sliderButtonColor = 0xFF808080;
     74 static const unsigned int textColor = 0xFFFFFFFF;
     75 
     76 HUDButton::HUDButton(HUDButtonType type, const IntPoint& position)
     77     : HUDWidget(IntRect(position, IntSize()))
     78     , m_type(type)
     79     , m_showAltButton(false)
     80 {
     81     const char* buttonResource = 0;
     82     const char* buttonResourceAlt = 0;
     83     switch (m_type) {
     84     case PlayPauseButton:
     85         buttonResource = "fsVideoPlay";
     86         buttonResourceAlt = "fsVideoPause";
     87         break;
     88     case TimeSliderButton:
     89         break;
     90     case VolumeUpButton:
     91         buttonResource = "fsVideoAudioVolumeHigh";
     92         break;
     93     case VolumeSliderButton:
     94         break;
     95     case VolumeDownButton:
     96         buttonResource = "fsVideoAudioVolumeLow";
     97         break;
     98     case ExitFullscreenButton:
     99         buttonResource = "fsVideoExitFullscreen";
    100         break;
    101     }
    102 
    103     if (buttonResource) {
    104         m_buttonImage = Image::loadPlatformResource(buttonResource);
    105         m_rect.setWidth(m_buttonImage->width());
    106         m_rect.setHeight(m_buttonImage->height());
    107     }
    108     if (buttonResourceAlt)
    109         m_buttonImageAlt = Image::loadPlatformResource(buttonResourceAlt);
    110 }
    111 
    112 void HUDButton::draw(GraphicsContext& context)
    113 {
    114     Image* image = (m_showAltButton && m_buttonImageAlt) ? m_buttonImageAlt.get() : m_buttonImage.get();
    115     context.drawImage(image, DeviceColorSpace, m_rect.location());
    116 }
    117 
    118 HUDSlider::HUDSlider(HUDSliderButtonShape shape, int buttonSize, const IntRect& rect)
    119     : HUDWidget(rect)
    120     , m_buttonShape(shape)
    121     , m_buttonSize(buttonSize)
    122     , m_buttonPosition(0)
    123     , m_dragStartOffset(0)
    124 {
    125 }
    126 
    127 void HUDSlider::draw(GraphicsContext& context)
    128 {
    129     // Draw gutter
    130     IntSize radius(m_rect.height() / 2, m_rect.height() / 2);
    131     context.fillRoundedRect(m_rect, radius, radius, radius, radius, Color(sliderGutterColor), DeviceColorSpace);
    132 
    133     // Draw button
    134     context.setStrokeColor(Color(sliderButtonColor), DeviceColorSpace);
    135     context.setFillColor(Color(sliderButtonColor), DeviceColorSpace);
    136 
    137     if (m_buttonShape == RoundButton) {
    138         context.drawEllipse(IntRect(m_rect.location().x() + m_buttonPosition, m_rect.location().y() - (m_buttonSize - m_rect.height()) / 2, m_buttonSize, m_buttonSize));
    139         return;
    140     }
    141 
    142     // Draw a diamond
    143     FloatPoint points[4];
    144     float half = static_cast<float>(m_buttonSize) / 2;
    145     points[0].setX(m_rect.location().x() + m_buttonPosition + half);
    146     points[0].setY(m_rect.location().y());
    147     points[1].setX(m_rect.location().x() + m_buttonPosition + m_buttonSize);
    148     points[1].setY(m_rect.location().y() + half);
    149     points[2].setX(m_rect.location().x() + m_buttonPosition + half);
    150     points[2].setY(m_rect.location().y() + m_buttonSize);
    151     points[3].setX(m_rect.location().x() + m_buttonPosition);
    152     points[3].setY(m_rect.location().y() + half);
    153     context.drawConvexPolygon(4, points, true);
    154 }
    155 
    156 void HUDSlider::drag(const IntPoint& point, bool start)
    157 {
    158     if (start) {
    159         // When we start, we need to snap the slider position to the x position if we clicked the gutter.
    160         // But if we click the button, we need to drag relative to where we clicked down. We only need
    161         // to check X because we would not even get here unless Y were already inside.
    162         int relativeX = point.x() - m_rect.location().x();
    163         if (relativeX >= m_buttonPosition && relativeX <= m_buttonPosition + m_buttonSize)
    164             m_dragStartOffset = point.x() - m_buttonPosition;
    165         else
    166             m_dragStartOffset = m_rect.location().x() + m_buttonSize / 2;
    167     }
    168 
    169     m_buttonPosition = max(0, min(m_rect.width() - m_buttonSize, point.x() - m_dragStartOffset));
    170 }
    171 
    172 FullscreenVideoController::FullscreenVideoController()
    173     : m_hudWindow(0)
    174     , m_videoWindow(0)
    175     , m_playPauseButton(HUDButton::PlayPauseButton, IntPoint((windowWidth - buttonSize) / 2, marginTop))
    176     , m_timeSliderButton(HUDButton::TimeSliderButton, IntPoint(0, 0))
    177     , m_volumeUpButton(HUDButton::VolumeUpButton, IntPoint(margin + buttonMiniSize + volumeSliderWidth + buttonMiniSize / 2, marginTop + (buttonSize - buttonMiniSize) / 2))
    178     , m_volumeSliderButton(HUDButton::VolumeSliderButton, IntPoint(0, 0))
    179     , m_volumeDownButton(HUDButton::VolumeDownButton, IntPoint(margin, marginTop + (buttonSize - buttonMiniSize) / 2))
    180     , m_exitFullscreenButton(HUDButton::ExitFullscreenButton, IntPoint(windowWidth - 2 * margin - buttonMiniSize, marginTop + (buttonSize - buttonMiniSize) / 2))
    181     , m_volumeSlider(HUDSlider::RoundButton, volumeSliderButtonSize, IntRect(IntPoint(margin + buttonMiniSize, marginTop + (buttonSize - buttonMiniSize) / 2 + buttonMiniSize / 2 - sliderHeight / 2), IntSize(volumeSliderWidth, sliderHeight)))
    182     , m_timeSlider(HUDSlider::DiamondButton, timeSliderButtonSize, IntRect(IntPoint(windowWidth / 2 - timeSliderWidth / 2, windowHeight - margin - sliderHeight), IntSize(timeSliderWidth, sliderHeight)))
    183     , m_hitWidget(0)
    184     , m_movingWindow(false)
    185     , m_timer(this, &FullscreenVideoController::timerFired)
    186 {
    187 }
    188 
    189 FullscreenVideoController::~FullscreenVideoController()
    190 {
    191     if (movie())
    192         movie()->exitFullscreen();
    193 }
    194 
    195 QTMovieWin* FullscreenVideoController::movie() const
    196 {
    197     return m_mediaElement ? reinterpret_cast<QTMovieWin*>(m_mediaElement->platformMedia().qtMovie) : 0;
    198 }
    199 
    200 void FullscreenVideoController::setMediaElement(HTMLMediaElement* mediaElement)
    201 {
    202     if (mediaElement == m_mediaElement)
    203         return;
    204 
    205     m_mediaElement = mediaElement;
    206     if (!m_mediaElement) {
    207         // Can't do full-screen, just get out
    208         exitFullscreen();
    209     }
    210 }
    211 
    212 void FullscreenVideoController::enterFullscreen()
    213 {
    214     if (!movie())
    215         return;
    216 
    217     m_videoWindow = movie()->enterFullscreen(this);
    218 
    219     RECT windowRect;
    220     GetClientRect(m_videoWindow, &windowRect);
    221     m_fullscreenSize.setWidth(windowRect.right - windowRect.left);
    222     m_fullscreenSize.setHeight(windowRect.bottom - windowRect.top);
    223 
    224     createHUDWindow();
    225 }
    226 
    227 void FullscreenVideoController::exitFullscreen()
    228 {
    229     if (movie())
    230         movie()->exitFullscreen();
    231 
    232     m_videoWindow = 0;
    233     SetWindowLongPtr(m_hudWindow, 0, 0);
    234     DestroyWindow(m_hudWindow);
    235     m_hudWindow = 0;
    236 }
    237 
    238 bool FullscreenVideoController::canPlay() const
    239 {
    240     return m_mediaElement && m_mediaElement->canPlay();
    241 }
    242 
    243 void FullscreenVideoController::play()
    244 {
    245     if (m_mediaElement)
    246         m_mediaElement->play(m_mediaElement->processingUserGesture());
    247 }
    248 
    249 void FullscreenVideoController::pause()
    250 {
    251     if (m_mediaElement)
    252         m_mediaElement->pause(m_mediaElement->processingUserGesture());
    253 }
    254 
    255 float FullscreenVideoController::volume() const
    256 {
    257     return m_mediaElement ? m_mediaElement->volume() : 0;
    258 }
    259 
    260 void FullscreenVideoController::setVolume(float volume)
    261 {
    262     if (m_mediaElement) {
    263         ExceptionCode ec;
    264         m_mediaElement->setVolume(volume, ec);
    265     }
    266 }
    267 
    268 float FullscreenVideoController::currentTime() const
    269 {
    270     return m_mediaElement ? m_mediaElement->currentTime() : 0;
    271 }
    272 
    273 void FullscreenVideoController::setCurrentTime(float value)
    274 {
    275     if (m_mediaElement) {
    276         ExceptionCode ec;
    277         m_mediaElement->setCurrentTime(value, ec);
    278     }
    279 }
    280 
    281 float FullscreenVideoController::duration() const
    282 {
    283     return m_mediaElement ? m_mediaElement->duration() : 0;
    284 }
    285 
    286 void FullscreenVideoController::beginScrubbing()
    287 {
    288     if (m_mediaElement)
    289         m_mediaElement->beginScrubbing();
    290 }
    291 
    292 void FullscreenVideoController::endScrubbing()
    293 {
    294     if (m_mediaElement)
    295         m_mediaElement->endScrubbing();
    296 }
    297 
    298 LRESULT FullscreenVideoController::fullscreenClientWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
    299 {
    300     switch (message) {
    301     case WM_CHAR:
    302         onChar(wParam);
    303         break;
    304     case WM_LBUTTONDOWN:
    305         onMouseDown(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
    306         break;
    307     case WM_MOUSEMOVE:
    308         onMouseMove(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
    309         break;
    310     case WM_LBUTTONUP:
    311         onMouseUp(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
    312         break;
    313     }
    314 
    315     return DefWindowProc(wnd, message, wParam, lParam);
    316 }
    317 
    318 static const LPCWSTR fullscreenVideeoHUDWindowClassName = L"fullscreenVideeoHUDWindowClass";
    319 
    320 void FullscreenVideoController::registerHUDWindowClass()
    321 {
    322     static bool haveRegisteredHUDWindowClass;
    323     if (haveRegisteredHUDWindowClass)
    324         return;
    325 
    326     haveRegisteredHUDWindowClass = true;
    327 
    328     WNDCLASSEX wcex;
    329 
    330     wcex.cbSize = sizeof(WNDCLASSEX);
    331 
    332     wcex.style = CS_HREDRAW | CS_VREDRAW;
    333     wcex.lpfnWndProc = hudWndProc;
    334     wcex.cbClsExtra = 0;
    335     wcex.cbWndExtra = 4;
    336     wcex.hInstance = gInstance;
    337     wcex.hIcon = 0;
    338     wcex.hCursor = LoadCursor(0, IDC_ARROW);
    339     wcex.hbrBackground = 0;
    340     wcex.lpszMenuName = 0;
    341     wcex.lpszClassName = fullscreenVideeoHUDWindowClassName;
    342     wcex.hIconSm = 0;
    343 
    344     RegisterClassEx(&wcex);
    345 }
    346 
    347 void FullscreenVideoController::createHUDWindow()
    348 {
    349     m_hudPosition.setX((m_fullscreenSize.width() - windowWidth) / 2);
    350     m_hudPosition.setY(m_fullscreenSize.height() * initialHUDPositionY - windowHeight / 2);
    351 
    352     // Local variable that will hold the returned pixels. No need to cleanup this value. It
    353     // will get cleaned up when m_bitmap is destroyed in the dtor
    354     void* pixels;
    355     BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(windowWidth, windowHeight));
    356     m_bitmap.set(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
    357 
    358     // Dirty the window so the HUD draws
    359     RECT clearRect = { m_hudPosition.x(), m_hudPosition.y(), m_hudPosition.x() + windowWidth, m_hudPosition.y() + windowHeight };
    360     InvalidateRect(m_videoWindow, &clearRect, true);
    361 
    362     m_playPauseButton.setShowAltButton(!canPlay());
    363     m_volumeSlider.setValue(volume());
    364     m_timeSlider.setValue(currentTime() / duration());
    365 
    366     if (!canPlay())
    367         m_timer.startRepeating(timerInterval);
    368 
    369     registerHUDWindowClass();
    370 
    371     m_hudWindow = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
    372         fullscreenVideeoHUDWindowClassName, 0, WS_POPUP | WS_VISIBLE,
    373         m_hudPosition.x(), m_hudPosition.y(), 0, 0, 0, 0, gInstance, 0);
    374     ASSERT(::IsWindow(m_hudWindow));
    375     SetWindowLongPtr(m_hudWindow, 0, reinterpret_cast<LONG_PTR>(this));
    376 
    377     draw();
    378 }
    379 
    380 static String timeToString(float time)
    381 {
    382     if (!isfinite(time))
    383         time = 0;
    384     int seconds = fabsf(time);
    385     int hours = seconds / (60 * 60);
    386     int minutes = (seconds / 60) % 60;
    387     seconds %= 60;
    388 
    389     if (hours) {
    390         if (hours > 9)
    391             return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
    392         return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
    393     }
    394 
    395     return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
    396 }
    397 
    398 void FullscreenVideoController::draw()
    399 {
    400     HDC windowDC = GetDC(m_hudWindow);
    401     HDC bitmapDC = CreateCompatibleDC(windowDC);
    402     ::ReleaseDC(m_hudWindow, windowDC);
    403     SelectObject(bitmapDC, m_bitmap.get());
    404 
    405     GraphicsContext context(bitmapDC, true);
    406 
    407     context.save();
    408 
    409     // Draw the background
    410     IntSize outerRadius(borderRadius, borderRadius);
    411     IntRect outerRect(0, 0, windowWidth, windowHeight);
    412     IntSize innerRadius(borderRadius - borderThickness, borderRadius - borderThickness);
    413     IntRect innerRect(borderThickness, borderThickness, windowWidth - borderThickness * 2, windowHeight - borderThickness * 2);
    414 
    415     context.fillRoundedRect(outerRect, outerRadius, outerRadius, outerRadius, outerRadius, Color(borderColor), DeviceColorSpace);
    416     context.setCompositeOperation(CompositeCopy);
    417     context.fillRoundedRect(innerRect, innerRadius, innerRadius, innerRadius, innerRadius, Color(backgroundColor), DeviceColorSpace);
    418 
    419     // Draw the widgets
    420     m_playPauseButton.draw(context);
    421     m_volumeUpButton.draw(context);
    422     m_volumeSliderButton.draw(context);
    423     m_volumeDownButton.draw(context);
    424     m_timeSliderButton.draw(context);
    425     m_exitFullscreenButton.draw(context);
    426     m_volumeSlider.draw(context);
    427     m_timeSlider.draw(context);
    428 
    429     // Draw the text strings
    430     FontDescription desc;
    431 
    432     NONCLIENTMETRICS metrics;
    433     metrics.cbSize = sizeof(metrics);
    434     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
    435     FontFamily family;
    436     family.setFamily(metrics.lfSmCaptionFont.lfFaceName);
    437     desc.setFamily(family);
    438 
    439     desc.setComputedSize(textSize);
    440     Font font = Font(desc, 0, 0);
    441     font.update(0);
    442 
    443     String s;
    444 
    445     // The y positioning of these two text strings is tricky because they are so small. They
    446     // are currently positioned relative to the center of the slider and then down the font
    447     // height / 4 (which is actually half of font height /2), which positions the center of
    448     // the text at the center of the slider.
    449     // Left string
    450     s = timeToString(currentTime());
    451     TextRun leftText(s);
    452     context.setFillColor(Color(textColor), DeviceColorSpace);
    453     context.drawText(font, leftText, IntPoint(windowWidth / 2 - timeSliderWidth / 2 - margin - font.width(leftText), windowHeight - margin - sliderHeight / 2 + font.height() / 4));
    454 
    455     // Right string
    456     s = timeToString(currentTime() - duration());
    457     TextRun rightText(s);
    458     context.setFillColor(Color(textColor), DeviceColorSpace);
    459     context.drawText(font, rightText, IntPoint(windowWidth / 2 + timeSliderWidth / 2 + margin, windowHeight - margin - sliderHeight / 2 + font.height() / 4));
    460 
    461     // Copy to the window
    462     BLENDFUNCTION blendFunction = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
    463     SIZE size = { windowWidth, windowHeight };
    464     POINT sourcePoint = {0, 0};
    465     POINT destPoint = { m_hudPosition.x(), m_hudPosition.y() };
    466     BOOL result = UpdateLayeredWindow(m_hudWindow, 0, &destPoint, &size, bitmapDC, &sourcePoint, 0, &blendFunction, ULW_ALPHA);
    467 
    468     context.restore();
    469 
    470     ::DeleteDC(bitmapDC);
    471 }
    472 
    473 LRESULT FullscreenVideoController::hudWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
    474 {
    475     LONG_PTR longPtr = GetWindowLongPtr(wnd, 0);
    476     FullscreenVideoController* controller = reinterpret_cast<FullscreenVideoController*>(longPtr);
    477     if (!controller)
    478         return DefWindowProc(wnd, message, wParam, lParam);
    479 
    480     switch (message) {
    481     case WM_CHAR:
    482         controller->onChar(wParam);
    483         break;
    484     case WM_LBUTTONDOWN:
    485         controller->onMouseDown(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
    486         break;
    487     case WM_MOUSEMOVE:
    488         controller->onMouseMove(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
    489         break;
    490     case WM_LBUTTONUP:
    491         controller->onMouseUp(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
    492         break;
    493     }
    494 
    495     return DefWindowProc(wnd, message, wParam, lParam);
    496 }
    497 
    498 void FullscreenVideoController::onChar(int c)
    499 {
    500     if (c == VK_ESCAPE) {
    501         if (m_mediaElement)
    502             m_mediaElement->exitFullscreen();
    503     } else if (c == VK_SPACE)
    504         togglePlay();
    505 }
    506 
    507 void FullscreenVideoController::timerFired(Timer<FullscreenVideoController>*)
    508 {
    509     // Update the time slider
    510     m_timeSlider.setValue(currentTime() / duration());
    511     draw();
    512 }
    513 
    514 void FullscreenVideoController::onMouseDown(const IntPoint& point)
    515 {
    516     IntPoint convertedPoint(fullScreenToHUDCoordinates(point));
    517 
    518     // Don't bother hit testing if we're outside the bounds of the window
    519     if (convertedPoint.x() < 0 || convertedPoint.x() >= windowWidth || convertedPoint.y() < 0 || convertedPoint.y() >= windowHeight)
    520         return;
    521 
    522     m_hitWidget = 0;
    523     m_movingWindow = false;
    524 
    525     if (m_playPauseButton.hitTest(convertedPoint))
    526         m_hitWidget = &m_playPauseButton;
    527     else if (m_exitFullscreenButton.hitTest(convertedPoint))
    528         m_hitWidget = &m_exitFullscreenButton;
    529     else if (m_volumeUpButton.hitTest(convertedPoint))
    530         m_hitWidget = &m_volumeUpButton;
    531     else if (m_volumeDownButton.hitTest(convertedPoint))
    532         m_hitWidget = &m_volumeDownButton;
    533     else if (m_volumeSlider.hitTest(convertedPoint)) {
    534         m_hitWidget = &m_volumeSlider;
    535         m_volumeSlider.drag(convertedPoint, true);
    536         setVolume(m_volumeSlider.value());
    537     } else if (m_timeSlider.hitTest(convertedPoint)) {
    538         m_hitWidget = &m_timeSlider;
    539         m_timeSlider.drag(convertedPoint, true);
    540         beginScrubbing();
    541         setCurrentTime(m_timeSlider.value() * duration());
    542     }
    543 
    544     // If we did not pick any of our widgets we are starting a window move
    545     if (!m_hitWidget) {
    546         m_moveOffset = convertedPoint;
    547         m_movingWindow = true;
    548     }
    549 
    550     draw();
    551 }
    552 
    553 void FullscreenVideoController::onMouseMove(const IntPoint& point)
    554 {
    555     IntPoint convertedPoint(fullScreenToHUDCoordinates(point));
    556 
    557     if (m_hitWidget) {
    558         m_hitWidget->drag(convertedPoint, false);
    559         if (m_hitWidget == &m_volumeSlider)
    560             setVolume(m_volumeSlider.value());
    561         else if (m_hitWidget == &m_timeSlider)
    562             setCurrentTime(m_timeSlider.value() * duration());
    563         draw();
    564     } else if (m_movingWindow)
    565         m_hudPosition.move(convertedPoint.x() - m_moveOffset.x(), convertedPoint.y() - m_moveOffset.y());
    566 }
    567 
    568 void FullscreenVideoController::onMouseUp(const IntPoint& point)
    569 {
    570     IntPoint convertedPoint(fullScreenToHUDCoordinates(point));
    571     m_movingWindow = false;
    572 
    573     if (m_hitWidget) {
    574         if (m_hitWidget == &m_playPauseButton && m_playPauseButton.hitTest(convertedPoint))
    575             togglePlay();
    576         else if (m_hitWidget == &m_volumeUpButton && m_volumeUpButton.hitTest(convertedPoint)) {
    577             setVolume(1);
    578             m_volumeSlider.setValue(1);
    579         } else if (m_hitWidget == &m_volumeDownButton && m_volumeDownButton.hitTest(convertedPoint)) {
    580             setVolume(0);
    581             m_volumeSlider.setValue(0);
    582         } else if (m_hitWidget == &m_timeSlider)
    583             endScrubbing();
    584         else if (m_hitWidget == &m_exitFullscreenButton && m_exitFullscreenButton.hitTest(convertedPoint)) {
    585             m_hitWidget = 0;
    586             if (m_mediaElement)
    587                 m_mediaElement->exitFullscreen();
    588             return;
    589         }
    590     }
    591 
    592     m_hitWidget = 0;
    593     draw();
    594 }
    595 
    596 void FullscreenVideoController::togglePlay()
    597 {
    598     if (canPlay())
    599         play();
    600     else
    601         pause();
    602 
    603     m_playPauseButton.setShowAltButton(!canPlay());
    604 
    605     // Run a timer while the video is playing so we can keep the time
    606     // slider and time values up to date.
    607     if (!canPlay())
    608         m_timer.startRepeating(timerInterval);
    609     else
    610         m_timer.stop();
    611 
    612     draw();
    613 }
    614 
    615 #endif
    616