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 43using namespace std; 44using namespace WebCore; 45 46static const float timerInterval = 0.033; 47 48// HUD Size 49static const int windowHeight = 59; 50static const int windowWidth = 438; 51 52// Margins and button sizes 53static const int margin = 9; 54static const int marginTop = 9; 55static const int buttonSize = 25; 56static const int buttonMiniSize = 16; 57static const int volumeSliderWidth = 50; 58static const int timeSliderWidth = 310; 59static const int sliderHeight = 8; 60static const int volumeSliderButtonSize = 10; 61static const int timeSliderButtonSize = 8; 62static const int textSize = 11; 63static const float initialHUDPositionY = 0.9; // Initial Y position of HUD in percentage from top of screen 64 65// Background values 66static const int borderRadius = 12; 67static const int borderThickness = 2; 68 69// Colors 70static const unsigned int backgroundColor = 0xA0202020; 71static const unsigned int borderColor = 0xFFA0A0A0; 72static const unsigned int sliderGutterColor = 0xFF141414; 73static const unsigned int sliderButtonColor = 0xFF808080; 74static const unsigned int textColor = 0xFFFFFFFF; 75 76HUDButton::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 112void 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 118HUDSlider::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 127void 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 156void 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 172FullscreenVideoController::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 189FullscreenVideoController::~FullscreenVideoController() 190{ 191 if (movie()) 192 movie()->exitFullscreen(); 193} 194 195QTMovieWin* FullscreenVideoController::movie() const 196{ 197 return m_mediaElement ? reinterpret_cast<QTMovieWin*>(m_mediaElement->platformMedia().qtMovie) : 0; 198} 199 200void 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 212void 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 227void 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 238bool FullscreenVideoController::canPlay() const 239{ 240 return m_mediaElement && m_mediaElement->canPlay(); 241} 242 243void FullscreenVideoController::play() 244{ 245 if (m_mediaElement) 246 m_mediaElement->play(m_mediaElement->processingUserGesture()); 247} 248 249void FullscreenVideoController::pause() 250{ 251 if (m_mediaElement) 252 m_mediaElement->pause(m_mediaElement->processingUserGesture()); 253} 254 255float FullscreenVideoController::volume() const 256{ 257 return m_mediaElement ? m_mediaElement->volume() : 0; 258} 259 260void FullscreenVideoController::setVolume(float volume) 261{ 262 if (m_mediaElement) { 263 ExceptionCode ec; 264 m_mediaElement->setVolume(volume, ec); 265 } 266} 267 268float FullscreenVideoController::currentTime() const 269{ 270 return m_mediaElement ? m_mediaElement->currentTime() : 0; 271} 272 273void FullscreenVideoController::setCurrentTime(float value) 274{ 275 if (m_mediaElement) { 276 ExceptionCode ec; 277 m_mediaElement->setCurrentTime(value, ec); 278 } 279} 280 281float FullscreenVideoController::duration() const 282{ 283 return m_mediaElement ? m_mediaElement->duration() : 0; 284} 285 286void FullscreenVideoController::beginScrubbing() 287{ 288 if (m_mediaElement) 289 m_mediaElement->beginScrubbing(); 290} 291 292void FullscreenVideoController::endScrubbing() 293{ 294 if (m_mediaElement) 295 m_mediaElement->endScrubbing(); 296} 297 298LRESULT 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 318static const LPCWSTR fullscreenVideeoHUDWindowClassName = L"fullscreenVideeoHUDWindowClass"; 319 320void 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 347void 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 380static 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 398void 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 473LRESULT 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 498void 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 507void FullscreenVideoController::timerFired(Timer<FullscreenVideoController>*) 508{ 509 // Update the time slider 510 m_timeSlider.setValue(currentTime() / duration()); 511 draw(); 512} 513 514void 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 553void 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 568void 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 596void 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