2 * Copyright (C) 2009 Apple Inc.
3 * Copyright (C) 2009 Google Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "RenderMediaControlsChromium.h"
32 #include "GraphicsContext.h"
33 #include "HTMLMediaElement.h"
34 #include "HTMLNames.h"
35 #include "PaintInfo.h"
36 #include "TimeRanges.h"
42 typedef WTF::HashMap<const char*, Image*> MediaControlImageMap;
43 static MediaControlImageMap* gMediaControlImageMap = 0;
45 static Image* platformResource(const char* name)
47 if (!gMediaControlImageMap)
48 gMediaControlImageMap = new MediaControlImageMap();
49 if (Image* image = gMediaControlImageMap->get(name))
51 if (Image* image = Image::loadPlatformResource(name).leakRef()) {
52 gMediaControlImageMap->set(name, image);
59 static bool hasSource(const HTMLMediaElement* mediaElement)
61 return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY
62 && mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE;
65 static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image)
67 context->drawImage(image, ColorSpaceDeviceRGB, rect);
71 static bool paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
73 HTMLMediaElement* mediaElement = toParentMediaElement(object);
77 static Image* soundFull = platformResource("mediaSoundFull");
78 static Image* soundNone = platformResource("mediaSoundNone");
79 static Image* soundDisabled = platformResource("mediaSoundDisabled");
81 if (!hasSource(mediaElement) || !mediaElement->hasAudio())
82 return paintMediaButton(paintInfo.context, rect, soundDisabled);
84 return paintMediaButton(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull);
87 static bool paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
89 HTMLMediaElement* mediaElement = toParentMediaElement(object);
93 static Image* mediaPlay = platformResource("mediaPlay");
94 static Image* mediaPause = platformResource("mediaPause");
95 static Image* mediaPlayDisabled = platformResource("mediaPlayDisabled");
97 if (!hasSource(mediaElement))
98 return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled);
100 return paintMediaButton(paintInfo.context, rect, mediaElement->canPlay() ? mediaPlay : mediaPause);
103 static Image* getMediaSliderThumb()
105 static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
106 return mediaSliderThumb;
109 static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
111 HTMLMediaElement* mediaElement = toParentMediaElement(object);
115 RenderStyle* style = object->style();
116 GraphicsContext* context = paintInfo.context;
118 // Draw the border of the time bar.
119 // FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first.
120 // https://bugs.webkit.org/show_bug.cgi?id=30143
122 context->setShouldAntialias(true);
123 context->setStrokeStyle(SolidStroke);
124 context->setStrokeColor(style->visitedDependentColor(CSSPropertyBorderLeftColor), ColorSpaceDeviceRGB);
125 context->setStrokeThickness(style->borderLeftWidth());
126 context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), ColorSpaceDeviceRGB);
127 context->drawRect(rect);
130 // Draw the buffered range. Since the element may have multiple buffered ranges and it'd be
131 // distracting/'busy' to show all of them, show only the buffered range containing the current play head.
132 IntRect bufferedRect = rect;
133 bufferedRect.inflate(-style->borderLeftWidth());
135 RefPtr<TimeRanges> bufferedTimeRanges = mediaElement->buffered();
136 float duration = mediaElement->duration();
137 float currentTime = mediaElement->currentTime();
138 if (isnan(duration) || isinf(duration) || !duration || isnan(currentTime))
141 for (unsigned i = 0; i < bufferedTimeRanges->length(); ++i) {
142 float start = bufferedTimeRanges->start(i, ASSERT_NO_EXCEPTION);
143 float end = bufferedTimeRanges->end(i, ASSERT_NO_EXCEPTION);
144 if (isnan(start) || isnan(end) || start > currentTime || end < currentTime)
146 float startFraction = start / duration;
147 float endFraction = end / duration;
148 float widthFraction = endFraction - startFraction;
149 bufferedRect.move(startFraction * bufferedRect.width(), 0);
150 bufferedRect.setWidth(widthFraction * bufferedRect.width());
152 // Don't bother drawing an empty area.
153 if (bufferedRect.isEmpty())
156 IntPoint sliderTopLeft = bufferedRect.location();
157 IntPoint sliderBottomLeft = sliderTopLeft;
158 sliderBottomLeft.move(0, bufferedRect.height());
160 RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderBottomLeft);
161 Color startColor = object->style()->visitedDependentColor(CSSPropertyColor);
162 gradient->addColorStop(0.0, startColor);
163 gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha()));
166 context->setStrokeStyle(NoStroke);
167 context->setFillGradient(gradient);
168 context->fillRect(bufferedRect);
176 static bool paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
178 ASSERT(object->node());
179 Node* hostNode = object->node()->shadowAncestorNode();
181 HTMLMediaElement* mediaElement = toParentMediaElement(hostNode);
185 if (!hasSource(mediaElement))
188 Image* mediaSliderThumb = getMediaSliderThumb();
189 return paintMediaButton(paintInfo.context, rect, mediaSliderThumb);
192 static bool paintMediaVolumeSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
194 HTMLMediaElement* mediaElement = toParentMediaElement(object);
198 GraphicsContext* context = paintInfo.context;
199 Color originalColor = context->strokeColor();
200 if (originalColor != Color::white)
201 context->setStrokeColor(Color::white, ColorSpaceDeviceRGB);
203 int y = rect.y() + rect.height() / 2;
204 context->drawLine(IntPoint(rect.x(), y), IntPoint(rect.x() + rect.width(), y));
206 if (originalColor != Color::white)
207 context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
211 static bool paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
213 static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
214 return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb);
217 static bool paintMediaTimelineContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
219 HTMLMediaElement* mediaElement = toParentMediaElement(object);
223 if (!rect.isEmpty()) {
224 GraphicsContext* context = paintInfo.context;
225 Color originalColor = context->strokeColor();
226 float originalThickness = context->strokeThickness();
227 StrokeStyle originalStyle = context->strokeStyle();
229 context->setStrokeStyle(SolidStroke);
231 // Draw the left border using CSS defined width and color.
232 context->setStrokeThickness(object->style()->borderLeftWidth());
233 context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), ColorSpaceDeviceRGB);
234 context->drawLine(IntPoint(rect.x() + 1, rect.y()),
235 IntPoint(rect.x() + 1, rect.y() + rect.height()));
237 // Draw the right border using CSS defined width and color.
238 context->setStrokeThickness(object->style()->borderRightWidth());
239 context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), ColorSpaceDeviceRGB);
240 context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()),
241 IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height()));
243 context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
244 context->setStrokeThickness(originalThickness);
245 context->setStrokeStyle(originalStyle);
250 static bool paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
252 HTMLMediaElement* mediaElement = toParentMediaElement(object);
256 DEFINE_STATIC_LOCAL(Image*, mediaFullscreen, (platformResource("mediaFullscreen")));
257 return paintMediaButton(paintInfo.context, rect, mediaFullscreen);
260 bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
263 case MediaMuteButton:
264 case MediaUnMuteButton:
265 return paintMediaMuteButton(object, paintInfo, rect);
266 case MediaPauseButton:
267 case MediaPlayButton:
268 return paintMediaPlayButton(object, paintInfo, rect);
270 return paintMediaSlider(object, paintInfo, rect);
271 case MediaSliderThumb:
272 return paintMediaSliderThumb(object, paintInfo, rect);
273 case MediaVolumeSlider:
274 return paintMediaVolumeSlider(object, paintInfo, rect);
275 case MediaVolumeSliderThumb:
276 return paintMediaVolumeSliderThumb(object, paintInfo, rect);
277 case MediaTimelineContainer:
278 return paintMediaTimelineContainer(object, paintInfo, rect);
279 case MediaEnterFullscreenButton:
280 case MediaExitFullscreenButton:
281 return paintMediaFullscreenButton(object, paintInfo, rect);
282 case MediaVolumeSliderMuteButton:
283 case MediaSeekBackButton:
284 case MediaSeekForwardButton:
285 case MediaVolumeSliderContainer:
286 case MediaCurrentTimeDisplay:
287 case MediaTimeRemainingDisplay:
288 case MediaControlsPanel:
289 case MediaRewindButton:
290 case MediaReturnToRealtimeButton:
291 case MediaStatusDisplay:
292 case MediaShowClosedCaptionsButton:
293 case MediaHideClosedCaptionsButton:
294 case MediaTextTrackDisplayContainer:
295 case MediaTextTrackDisplay:
296 case MediaFullScreenVolumeSlider:
297 case MediaFullScreenVolumeSliderThumb:
298 ASSERT_NOT_REACHED();
304 void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderStyle* style)
306 static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
307 static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
309 Image* thumbImage = 0;
310 if (style->appearance() == MediaSliderThumbPart)
311 thumbImage = mediaSliderThumb;
312 else if (style->appearance() == MediaVolumeSliderThumbPart)
313 thumbImage = mediaVolumeSliderThumb;
315 float zoomLevel = style->effectiveZoom();
317 style->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed));
318 style->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed));
322 #endif // #if ENABLE(VIDEO)
324 } // namespace WebCore