| /* |
| * 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 |