1/* 2 * Copyright (C) 2009, 2013 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 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 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 "RenderMediaControls.h" 31 32#include "GraphicsContext.h" 33#include "HTMLMediaElement.h" 34#include "HTMLNames.h" 35#include "PaintInfo.h" 36#include "RenderTheme.h" 37 38// FIXME: Unify more of the code for Mac and Win. 39#if PLATFORM(WIN) && USE(CG) 40 41#include <CoreGraphics/CoreGraphics.h> 42#include <WebKitSystemInterface/WebKitSystemInterface.h> 43 44// The Windows version of WKSI defines these functions as capitalized, while the Mac version defines them as lower case. 45// FIXME: Is this necessary anymore? 46inline bool wkHitTestMediaUIPart(int part, const CGRect& bounds, const CGPoint& point) 47{ 48 WKHitTestMediaUIPart(part, bounds, point); 49} 50 51inline void wkMeasureMediaUIPart(int part, CGRect* bounds, CGSize* naturalSize) 52{ 53 WKMeasureMediaUIPart(part, bounds, naturalSize); 54} 55 56inline void wkDrawMediaUIPart(int part, CGContextRef context, const CGRect& rect, unsigned state) 57{ 58 WKDrawMediaUIPart(part, context, rect, state); 59} 60 61inline void wkDrawMediaSliderTrack(CGContextRef context, const CGRect& rect, float timeLoaded, float currentTime, float duration, unsigned state) 62{ 63 WKDrawMediaSliderTrack(context, rect, timeLoaded, currentTime, duration, state); 64} 65 66#endif 67 68 69namespace WebCore { 70 71#if PLATFORM(WIN) && USE(CG) 72 73static WKMediaControllerThemeState determineState(const RenderObject& o) 74{ 75 int result = 0; 76 const RenderTheme& theme = o.theme(); 77 if (!theme.isEnabled(o) || theme.isReadOnlyControl(o)) 78 result |= WKMediaControllerFlagDisabled; 79 if (theme.isPressed(o)) 80 result |= WKMediaControllerFlagPressed; 81 if (theme.isFocused(o)) 82 result |= WKMediaControllerFlagFocused; 83 return static_cast<WKMediaControllerThemeState>(result); 84} 85 86// Utility to scale when the UI part are not scaled by wkDrawMediaUIPart 87static FloatRect getUnzoomedRectAndAdjustCurrentContext(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &originalRect) 88{ 89 float zoomLevel = o.style().effectiveZoom(); 90 FloatRect unzoomedRect(originalRect); 91 if (zoomLevel != 1.0f) { 92 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 93 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 94 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); 95 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 96 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 97 } 98 return unzoomedRect; 99} 100 101static const int mediaSliderThumbWidth = 13; 102static const int mediaSliderThumbHeight = 14; 103 104void RenderMediaControls::adjustMediaSliderThumbSize(RenderStyle& style) 105{ 106 int part; 107 switch (style.appearance()) { 108 case MediaSliderThumbPart: 109 part = MediaSliderThumb; 110 break; 111 case MediaVolumeSliderThumbPart: 112 part = MediaVolumeSliderThumb; 113 break; 114 case MediaFullScreenVolumeSliderThumbPart: 115 part = MediaFullScreenVolumeSliderThumb; 116 break; 117 default: 118 return; 119 } 120 121 CGSize size; 122 wkMeasureMediaUIPart(part, 0, &size); 123 124 float zoomLevel = style.effectiveZoom(); 125 style.setWidth(Length(static_cast<int>(size.width * zoomLevel), Fixed)); 126 style.setHeight(Length(static_cast<int>(size.height * zoomLevel), Fixed)); 127} 128 129bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r) 130{ 131 GraphicsContextStateSaver stateSaver(*paintInfo.context); 132 133 switch (part) { 134 case MediaEnterFullscreenButton: 135 case MediaExitFullscreenButton: 136 if (MediaControlFullscreenButtonElement* btn = static_cast<MediaControlFullscreenButtonElement*>(o.node())) { 137 bool enterButton = btn->displayType() == MediaEnterFullscreenButton; 138 wkDrawMediaUIPart(enterButton ? WKMediaUIPartFullscreenButton : WKMediaUIPartExitFullscreenButton, paintInfo.context->platformContext(), r, determineState(o)); 139 } 140 break; 141 case MediaShowClosedCaptionsButton: 142 case MediaHideClosedCaptionsButton: 143 if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o.node())) { 144 bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton; 145 wkDrawMediaUIPart(captionsVisible ? WKMediaUIPartHideClosedCaptionsButton : WKMediaUIPartShowClosedCaptionsButton, paintInfo.context->platformContext(), r, determineState(o)); 146 } 147 break; 148 case MediaMuteButton: 149 case MediaUnMuteButton: 150 if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o.node())) { 151 bool audioEnabled = btn->displayType() == MediaMuteButton; 152 wkDrawMediaUIPart(audioEnabled ? WKMediaUIPartMuteButton : WKMediaUIPartUnMuteButton, paintInfo.context->platformContext(), r, determineState(o)); 153 } 154 break; 155 case MediaPauseButton: 156 case MediaPlayButton: 157 if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o.node())) { 158 bool canPlay = btn->displayType() == MediaPlayButton; 159 wkDrawMediaUIPart(canPlay ? WKMediaUIPartPlayButton : WKMediaUIPartPauseButton, paintInfo.context->platformContext(), r, determineState(o)); 160 } 161 break; 162 case MediaRewindButton: 163 wkDrawMediaUIPart(WKMediaUIPartRewindButton, paintInfo.context->platformContext(), r, determineState(o)); 164 break; 165 case MediaReturnToRealtimeButton: 166 wkDrawMediaUIPart(WKMediaUIPartSeekToRealtimeButton, paintInfo.context->platformContext(), r, determineState(o)); 167 break; 168 case MediaSeekBackButton: 169 wkDrawMediaUIPart(WKMediaUIPartSeekBackButton, paintInfo.context->platformContext(), r, determineState(o)); 170 break; 171 case MediaSeekForwardButton: 172 wkDrawMediaUIPart(WKMediaUIPartSeekForwardButton, paintInfo.context->platformContext(), r, determineState(o)); 173 break; 174 case MediaSlider: { 175 if (HTMLMediaElement* mediaElement = parentMediaElement(o)) { 176 FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r); 177 wkDrawMediaSliderTrack(paintInfo.context->platformContext(), unzoomedRect, mediaElement->percentLoaded() * mediaElement->duration(), mediaElement->currentTime(), mediaElement->duration(), determineState(o)); 178 } 179 break; 180 } 181 case MediaSliderThumb: 182 wkDrawMediaUIPart(WKMediaUIPartTimelineSliderThumb, paintInfo.context->platformContext(), r, determineState(o)); 183 break; 184 case MediaVolumeSliderContainer: 185 wkDrawMediaUIPart(WKMediaUIPartVolumeSliderContainer, paintInfo.context->platformContext(), r, determineState(o)); 186 break; 187 case MediaVolumeSlider: 188 wkDrawMediaUIPart(WKMediaUIPartVolumeSlider, paintInfo.context->platformContext(), r, determineState(o)); 189 break; 190 case MediaVolumeSliderThumb: 191 wkDrawMediaUIPart(WKMediaUIPartVolumeSliderThumb, paintInfo.context->platformContext(), r, determineState(o)); 192 break; 193 case MediaFullScreenVolumeSlider: 194 wkDrawMediaUIPart(WKMediaUIPartFullScreenVolumeSlider, paintInfo.context->platformContext(), r, determineState(o)); 195 break; 196 case MediaFullScreenVolumeSliderThumb: 197 wkDrawMediaUIPart(WKMediaUIPartFullScreenVolumeSliderThumb, paintInfo.context->platformContext(), r, determineState(o)); 198 break; 199 case MediaTimelineContainer: 200 wkDrawMediaUIPart(WKMediaUIPartBackground, paintInfo.context->platformContext(), r, determineState(o)); 201 break; 202 case MediaCurrentTimeDisplay: 203 ASSERT_NOT_REACHED(); 204 break; 205 case MediaTimeRemainingDisplay: 206 ASSERT_NOT_REACHED(); 207 break; 208 case MediaControlsPanel: 209 ASSERT_NOT_REACHED(); 210 case MediaTextTrackDisplayContainer: 211 case MediaTextTrackDisplay: 212 case MediaClosedCaptionsContainer: 213 case MediaClosedCaptionsTrackList: 214 ASSERT_NOT_REACHED(); 215 break; 216 } 217 218 return false; 219} 220 221#endif 222 223IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) 224{ 225 static const int xOffset = -4; 226 static const int yOffset = 5; 227 228 float zoomLevel = muteButtonBox->style().effectiveZoom(); 229 int y = yOffset * zoomLevel + muteButtonBox->pixelSnappedOffsetHeight() - size.height(); 230 FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), IsFixed | UseTransforms); 231 if (absPoint.y() < 0) 232 y = muteButtonBox->pixelSnappedHeight(); 233 return IntPoint(xOffset * zoomLevel, y); 234} 235 236} 237 238#endif 239