2010-09-09 Jer Noble <jer.noble@apple.com>
[WebKit-https.git] / WebCore / rendering / RenderMediaControls.cpp
1 /*
2  * Copyright (C) 2009 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 #include "RenderMediaControls.h"
28
29 #include "GraphicsContext.h"
30 #include "HTMLMediaElement.h"
31 #include "HTMLNames.h"
32 #include "RenderTheme.h"
33 #include <CoreGraphics/CoreGraphics.h>
34 #include <WebKitSystemInterface/WebKitSystemInterface.h>
35
36 #if PLATFORM(WIN)
37 // The Windows version of WKSI defines these functions as capitalized, while the Mac version defines them as lower case.
38 #define wkMediaControllerThemeAvailable(themeStyle) WKMediaControllerThemeAvailable(themeStyle)
39 #define wkHitTestMediaUIPart(part, themeStyle, bounds, point) WKHitTestMediaUIPart(part, themeStyle, bounds, point)
40 #define wkMeasureMediaUIPart(part, themeStyle, bounds, naturalSize) WKMeasureMediaUIPart(part, themeStyle, bounds, naturalSize)
41 #define wkDrawMediaUIPart(part, themeStyle, context, rect, state) WKDrawMediaUIPart(part, themeStyle, context, rect, state)
42 #define wkDrawMediaSliderTrack(themeStyle, context, rect, timeLoaded, currentTime, duration, state) WKDrawMediaSliderTrack(themeStyle, context, rect, timeLoaded, currentTime, duration, state)
43 #endif
44  
45 using namespace std;
46  
47 namespace WebCore {
48
49 #if ENABLE(VIDEO)
50
51 static WKMediaControllerThemeState determineState(RenderObject* o)
52 {
53     int result = 0;
54     RenderTheme* theme = o->theme();
55     if (!theme->isEnabled(o) || theme->isReadOnlyControl(o))
56         result |= WKMediaControllerFlagDisabled;
57     if (theme->isPressed(o))
58         result |= WKMediaControllerFlagPressed;
59     if (theme->isFocused(o))
60         result |= WKMediaControllerFlagFocused;
61     return static_cast<WKMediaControllerThemeState>(result);
62 }
63
64 // Utility to scale when the UI part are not scaled by wkDrawMediaUIPart
65 static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const PaintInfo& paintInfo, const IntRect &originalRect)
66 {
67     float zoomLevel = o->style()->effectiveZoom();
68     FloatRect unzoomedRect(originalRect);
69     if (zoomLevel != 1.0f) {
70         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
71         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
72         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
73         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
74         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
75     }
76     return unzoomedRect;
77 }
78
79 static const int mediaSliderThumbWidth = 13;
80 static const int mediaSliderThumbHeight = 14;
81
82 void RenderMediaControls::adjustMediaSliderThumbSize(RenderObject* o)
83 {
84     ControlPart part = o->style()->appearance();
85
86     if (part != MediaSliderThumbPart && part != MediaVolumeSliderThumbPart)
87         return;
88
89     CGSize size;
90     wkMeasureMediaUIPart(part == MediaSliderThumbPart ? MediaSliderThumb : MediaVolumeSliderThumb, WKMediaControllerThemeQuickTime, 0, &size);
91
92     float zoomLevel = o->style()->effectiveZoom();
93     o->style()->setWidth(Length(static_cast<int>(size.width * zoomLevel), Fixed));
94     o->style()->setHeight(Length(static_cast<int>(size.height * zoomLevel), Fixed));
95 }
96
97 bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
98 {
99     static const int themeStyle = WKMediaControllerThemeQuickTime;
100     paintInfo.context->save();
101     switch (part) {
102         case MediaFullscreenButton:
103             wkDrawMediaUIPart(WKMediaUIPartFullscreenButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
104             break;
105         case MediaShowClosedCaptionsButton:
106         case MediaHideClosedCaptionsButton:
107             if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o->node())) {
108                 bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton;
109                 wkDrawMediaUIPart(captionsVisible ? WKMediaUIPartHideClosedCaptionsButton : WKMediaUIPartShowClosedCaptionsButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
110             }
111             break;
112         case MediaMuteButton:
113         case MediaUnMuteButton:
114             if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) {
115                 bool audioEnabled = btn->displayType() == MediaMuteButton;
116                 wkDrawMediaUIPart(audioEnabled ? WKMediaUIPartMuteButton : WKMediaUIPartUnMuteButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
117             }
118             break;
119         case MediaPauseButton:
120         case MediaPlayButton:
121             if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
122                 bool canPlay = btn->displayType() == MediaPlayButton;
123                 wkDrawMediaUIPart(canPlay ? WKMediaUIPartPlayButton : WKMediaUIPartPauseButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
124             }
125             break;
126         case MediaRewindButton:
127             wkDrawMediaUIPart(WKMediaUIPartRewindButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
128             break;
129         case MediaSeekBackButton:
130             wkDrawMediaUIPart(WKMediaUIPartSeekBackButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
131             break;
132         case MediaSeekForwardButton:
133             wkDrawMediaUIPart(WKMediaUIPartSeekForwardButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
134             break;
135         case MediaSlider: {
136             if (HTMLMediaElement* mediaElement = toParentMediaElement(o)) {
137                 FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
138                 wkDrawMediaSliderTrack(themeStyle, paintInfo.context->platformContext(), unzoomedRect, mediaElement->percentLoaded() * mediaElement->duration(), mediaElement->currentTime(), mediaElement->duration(), determineState(o));
139             }
140             break;
141         }
142         case MediaSliderThumb:
143             wkDrawMediaUIPart(WKMediaUIPartTimelineSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
144             break;
145         case MediaVolumeSliderContainer:
146             wkDrawMediaUIPart(WKMediaUIPartVolumeSliderContainer, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
147             break;
148         case MediaVolumeSlider:
149             wkDrawMediaUIPart(WKMediaUIPartVolumeSlider, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
150             break;
151         case MediaVolumeSliderThumb:
152             wkDrawMediaUIPart(WKMediaUIPartVolumeSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
153             break;
154         case MediaTimelineContainer:
155             wkDrawMediaUIPart(WKMediaUIPartBackground, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
156             break;
157         case MediaCurrentTimeDisplay:
158             ASSERT_NOT_REACHED();
159             break;
160         case MediaTimeRemainingDisplay:
161             ASSERT_NOT_REACHED();
162             break;
163         case MediaControlsPanel:
164             ASSERT_NOT_REACHED();
165             break;
166     }
167     paintInfo.context->restore();
168
169     return false;
170 }
171
172 IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size)
173 {
174     static const int xOffset = -4;
175     static const int yOffset = 5;
176
177     float zoomLevel = muteButton->renderer()->style()->effectiveZoom();
178     int y = yOffset * zoomLevel + muteButton->renderBox()->offsetHeight() - size.height();
179     FloatPoint absPoint = muteButton->renderer()->localToAbsolute(FloatPoint(muteButton->renderBox()->offsetLeft(), y), true, true);
180     if (absPoint.y() < 0)
181         y = muteButton->renderBox()->height();
182     return IntPoint(xOffset * zoomLevel, y);
183
184 }
185 #endif  // #if ENABLE(VIDEO)
186
187 } // namespace WebCore