/* | |
* Copyright (C) 2009 Apple Inc. | |
* Copyright (C) 2009 Google Inc. | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
#include "config.h" | |
#include "RenderMediaControlsChromium.h" | |
#include "Gradient.h" | |
#include "GraphicsContext.h" | |
#include "HTMLMediaElement.h" | |
#include "HTMLNames.h" | |
namespace WebCore { | |
#if ENABLE(VIDEO) | |
typedef WTF::HashMap<const char*, Image*> MediaControlImageMap; | |
static MediaControlImageMap* gMediaControlImageMap = 0; | |
static Image* platformResource(const char* name) | |
{ | |
if (!gMediaControlImageMap) | |
gMediaControlImageMap = new MediaControlImageMap(); | |
if (Image* image = gMediaControlImageMap->get(name)) | |
return image; | |
if (Image* image = Image::loadPlatformResource(name).releaseRef()) { | |
gMediaControlImageMap->set(name, image); | |
return image; | |
} | |
ASSERT_NOT_REACHED(); | |
return 0; | |
} | |
static bool hasSource(const HTMLMediaElement* mediaElement) | |
{ | |
return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY | |
&& mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE; | |
} | |
static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image) | |
{ | |
IntRect imageRect = image->rect(); | |
context->drawImage(image, DeviceColorSpace, rect); | |
return true; | |
} | |
static bool paintMediaMuteButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
HTMLMediaElement* mediaElement = toParentMediaElement(object); | |
if (!mediaElement) | |
return false; | |
static Image* soundFull = platformResource("mediaSoundFull"); | |
static Image* soundNone = platformResource("mediaSoundNone"); | |
static Image* soundDisabled = platformResource("mediaSoundDisabled"); | |
if (!hasSource(mediaElement) || !mediaElement->hasAudio()) | |
return paintMediaButton(paintInfo.context, rect, soundDisabled); | |
return paintMediaButton(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull); | |
} | |
static bool paintMediaPlayButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
HTMLMediaElement* mediaElement = toParentMediaElement(object); | |
if (!mediaElement) | |
return false; | |
static Image* mediaPlay = platformResource("mediaPlay"); | |
static Image* mediaPause = platformResource("mediaPause"); | |
static Image* mediaPlayDisabled = platformResource("mediaPlayDisabled"); | |
if (!hasSource(mediaElement)) | |
return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled); | |
return paintMediaButton(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); | |
} | |
static bool paintMediaSlider(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
HTMLMediaElement* mediaElement = toParentMediaElement(object); | |
if (!mediaElement) | |
return false; | |
RenderStyle* style = object->style(); | |
GraphicsContext* context = paintInfo.context; | |
// Draw the border of the time bar. | |
// FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first. | |
// https://bugs.webkit.org/show_bug.cgi?id=30143 | |
context->save(); | |
context->setShouldAntialias(true); | |
context->setStrokeStyle(SolidStroke); | |
context->setStrokeColor(style->borderLeftColor(), DeviceColorSpace); | |
context->setStrokeThickness(style->borderLeftWidth()); | |
context->setFillColor(style->backgroundColor(), DeviceColorSpace); | |
context->drawRect(rect); | |
context->restore(); | |
// Draw the buffered ranges. | |
// FIXME: Draw multiple ranges if there are multiple buffered ranges. | |
IntRect bufferedRect = rect; | |
bufferedRect.inflate(-style->borderLeftWidth()); | |
bufferedRect.setWidth((bufferedRect.width() * mediaElement->percentLoaded())); | |
// Don't bother drawing an empty area. | |
if (!bufferedRect.isEmpty()) { | |
IntPoint sliderTopLeft = bufferedRect.location(); | |
IntPoint sliderTopRight = sliderTopLeft; | |
sliderTopRight.move(0, bufferedRect.height()); | |
RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight); | |
Color startColor = object->style()->color(); | |
gradient->addColorStop(0.0, startColor); | |
gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha())); | |
context->save(); | |
context->setStrokeStyle(NoStroke); | |
context->setFillGradient(gradient); | |
context->fillRect(bufferedRect); | |
context->restore(); | |
} | |
return true; | |
} | |
static bool paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
if (!object->parent()->isSlider()) | |
return false; | |
HTMLMediaElement* mediaElement = toParentMediaElement(object->parent()); | |
if (!mediaElement) | |
return false; | |
if (!hasSource(mediaElement)) | |
return true; | |
static Image* mediaSliderThumb = platformResource("mediaSliderThumb"); | |
return paintMediaButton(paintInfo.context, rect, mediaSliderThumb); | |
} | |
static bool paintMediaVolumeSlider(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
HTMLMediaElement* mediaElement = toParentMediaElement(object); | |
if (!mediaElement) | |
return false; | |
GraphicsContext* context = paintInfo.context; | |
Color originalColor = context->strokeColor(); | |
if (originalColor != Color::white) | |
context->setStrokeColor(Color::white, DeviceColorSpace); | |
int x = rect.x() + rect.width() / 2; | |
context->drawLine(IntPoint(x, rect.y()), IntPoint(x, rect.y() + rect.height())); | |
if (originalColor != Color::white) | |
context->setStrokeColor(originalColor, DeviceColorSpace); | |
return true; | |
} | |
static bool paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
if (!object->parent()->isSlider()) | |
return false; | |
static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb"); | |
return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb); | |
} | |
static bool paintMediaTimelineContainer(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
HTMLMediaElement* mediaElement = toParentMediaElement(object); | |
if (!mediaElement) | |
return false; | |
if (!rect.isEmpty()) { | |
GraphicsContext* context = paintInfo.context; | |
Color originalColor = context->strokeColor(); | |
float originalThickness = context->strokeThickness(); | |
StrokeStyle originalStyle = context->strokeStyle(); | |
context->setStrokeStyle(SolidStroke); | |
// Draw the left border using CSS defined width and color. | |
context->setStrokeThickness(object->style()->borderLeftWidth()); | |
context->setStrokeColor(object->style()->borderLeftColor().rgb(), DeviceColorSpace); | |
context->drawLine(IntPoint(rect.x() + 1, rect.y()), | |
IntPoint(rect.x() + 1, rect.y() + rect.height())); | |
// Draw the right border using CSS defined width and color. | |
context->setStrokeThickness(object->style()->borderRightWidth()); | |
context->setStrokeColor(object->style()->borderRightColor().rgb(), DeviceColorSpace); | |
context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()), | |
IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height())); | |
context->setStrokeColor(originalColor, DeviceColorSpace); | |
context->setStrokeThickness(originalThickness); | |
context->setStrokeStyle(originalStyle); | |
} | |
return true; | |
} | |
bool RenderMediaControlsChromium::shouldRenderMediaControlPart(ControlPart part, Element* e) | |
{ | |
UNUSED_PARAM(e); | |
switch (part) { | |
case MediaMuteButtonPart: | |
case MediaPlayButtonPart: | |
case MediaSliderPart: | |
case MediaSliderThumbPart: | |
case MediaVolumeSliderContainerPart: | |
case MediaVolumeSliderPart: | |
case MediaVolumeSliderThumbPart: | |
case MediaControlsBackgroundPart: | |
case MediaCurrentTimePart: | |
case MediaTimeRemainingPart: | |
return true; | |
default: | |
; | |
} | |
return false; | |
} | |
bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) | |
{ | |
switch (part) { | |
case MediaMuteButton: | |
case MediaUnMuteButton: | |
return paintMediaMuteButton(object, paintInfo, rect); | |
case MediaPauseButton: | |
case MediaPlayButton: | |
return paintMediaPlayButton(object, paintInfo, rect); | |
case MediaSlider: | |
return paintMediaSlider(object, paintInfo, rect); | |
case MediaSliderThumb: | |
return paintMediaSliderThumb(object, paintInfo, rect); | |
case MediaVolumeSlider: | |
return paintMediaVolumeSlider(object, paintInfo, rect); | |
case MediaVolumeSliderThumb: | |
return paintMediaVolumeSliderThumb(object, paintInfo, rect); | |
case MediaTimelineContainer: | |
return paintMediaTimelineContainer(object, paintInfo, rect); | |
case MediaFullscreenButton: | |
case MediaSeekBackButton: | |
case MediaSeekForwardButton: | |
case MediaVolumeSliderContainer: | |
case MediaCurrentTimeDisplay: | |
case MediaTimeRemainingDisplay: | |
case MediaControlsPanel: | |
case MediaRewindButton: | |
case MediaReturnToRealtimeButton: | |
case MediaStatusDisplay: | |
case MediaShowClosedCaptionsButton: | |
case MediaHideClosedCaptionsButton: | |
ASSERT_NOT_REACHED(); | |
break; | |
} | |
return false; | |
} | |
void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderObject* object) | |
{ | |
static Image* mediaSliderThumb = platformResource("mediaSliderThumb"); | |
static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb"); | |
Image* thumbImage = 0; | |
if (object->style()->appearance() == MediaSliderThumbPart) | |
thumbImage = mediaSliderThumb; | |
else if (object->style()->appearance() == MediaVolumeSliderThumbPart) | |
thumbImage = mediaVolumeSliderThumb; | |
float zoomLevel = object->style()->effectiveZoom(); | |
if (thumbImage) { | |
object->style()->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed)); | |
object->style()->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed)); | |
} | |
} | |
#endif // #if ENABLE(VIDEO) | |
} // namespace WebCore |