/* * 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" #include "PaintInfo.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, ColorSpaceDeviceRGB, rect); return true; } static bool paintMediaMuteButton(RenderObject* object, const 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 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->canPlay() ? mediaPlay : mediaPause); } static Image* getMediaSliderThumb() { static Image* mediaSliderThumb = platformResource("mediaSliderThumb"); return mediaSliderThumb; } static bool paintMediaSlider(RenderObject* object, const 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->visitedDependentColor(CSSPropertyBorderLeftColor), ColorSpaceDeviceRGB); context->setStrokeThickness(style->borderLeftWidth()); context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), ColorSpaceDeviceRGB); 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()); double bufferedWidth = 0.0; if (mediaElement->percentLoaded() > 0.0) { // Account for the width of the slider thumb. Image* mediaSliderThumb = getMediaSliderThumb(); double thumbWidth = mediaSliderThumb->width() / 2.0 + 1.0; double rectWidth = bufferedRect.width() - thumbWidth; if (rectWidth < 0.0) rectWidth = 0.0; bufferedWidth = rectWidth * mediaElement->percentLoaded() + thumbWidth; } bufferedRect.setWidth(bufferedWidth); // 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()->visitedDependentColor(CSSPropertyColor); 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 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; Image* mediaSliderThumb = getMediaSliderThumb(); return paintMediaButton(paintInfo.context, rect, mediaSliderThumb); } static bool paintMediaVolumeSlider(RenderObject* object, const 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, ColorSpaceDeviceRGB); 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, ColorSpaceDeviceRGB); return true; } static bool paintMediaVolumeSliderThumb(RenderObject* object, const 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 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()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), ColorSpaceDeviceRGB); 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()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), ColorSpaceDeviceRGB); context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()), IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height())); context->setStrokeColor(originalColor, ColorSpaceDeviceRGB); context->setStrokeThickness(originalThickness); context->setStrokeStyle(originalStyle); } return true; } bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const 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 MediaVolumeSliderMuteButton: 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