blob: f1ac387d140c8d2ce88ca19cc4d42516a34f0315 [file] [log] [blame]
/*
* 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 "core/paint/MediaControlsPainter.h"
#include "bindings/core/v8/ExceptionStatePlaceholder.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/TimeRanges.h"
#include "core/html/shadow/MediaControlElementTypes.h"
#include "core/layout/LayoutBox.h"
#include "core/paint/PaintInfo.h"
#include "core/style/ComputedStyle.h"
#include "platform/graphics/Gradient.h"
#include "platform/graphics/GraphicsContext.h"
namespace blink {
static const double kCurrentTimeBufferedDelta = 1.0;
typedef WTF::HashMap<const char*, Image*> MediaControlImageMap;
static MediaControlImageMap* gMediaControlImageMap = 0;
// Current UI slider thumbs sizes.
static const int mediaSliderThumbWidth = 32;
static const int mediaSliderThumbHeight = 24;
static const int mediaVolumeSliderThumbHeight = 24;
static const int mediaVolumeSliderThumbWidth = 24;
// New UI slider thumb sizes, shard between time and volume.
static const int mediaSliderThumbTouchWidthNew = 36; // Touch zone size.
static const int mediaSliderThumbTouchHeightNew = 48;
static const int mediaSliderThumbPaintWidthNew = 12; // Painted area.
static const int mediaSliderThumbPaintHeightNew = 12;
// New UI overlay play button size.
static const int mediaOverlayPlayButtonWidthNew = 48;
static const int mediaOverlayPlayButtonHeightNew = 48;
// Alpha for disabled elements.
static const float kDisabledAlpha = 0.4;
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).leakRef()) {
gMediaControlImageMap->set(name, image);
return image;
}
ASSERT_NOT_REACHED();
return 0;
}
static Image* platformResource(const char* currentName, const char* newName) {
// Return currentName or newName based on current or new playback.
return platformResource(RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()
? newName
: currentName);
}
static bool hasSource(const HTMLMediaElement* mediaElement) {
return mediaElement->getNetworkState() != HTMLMediaElement::kNetworkEmpty &&
mediaElement->getNetworkState() != HTMLMediaElement::kNetworkNoSource;
}
static FloatRect adjustRectForPadding(IntRect rect,
const LayoutObject* object) {
FloatRect adjustedRect(rect);
if (!object)
return adjustedRect;
// TODO(liberato): make this more elegant, crbug.com/598861 .
if (const ComputedStyle* style = object->style()) {
const float paddingLeft = style->paddingLeft().getFloatValue();
const float paddingTop = style->paddingTop().getFloatValue();
const float paddingRight = style->paddingRight().getFloatValue();
const float paddingBottom = style->paddingBottom().getFloatValue();
adjustedRect = FloatRect(rect.x() + paddingLeft, rect.y() + paddingTop,
rect.width() - paddingLeft - paddingRight,
rect.height() - paddingTop - paddingBottom);
}
return adjustedRect;
}
static bool paintMediaButton(GraphicsContext& context,
const IntRect& rect,
Image* image,
const LayoutObject* object,
bool isEnabled) {
if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
context.drawImage(image, rect);
return true;
}
FloatRect drawRect = adjustRectForPadding(rect, object);
if (!isEnabled)
context.beginLayer(kDisabledAlpha);
context.drawImage(image, drawRect);
if (!isEnabled)
context.endLayer();
return true;
}
static bool paintMediaButton(GraphicsContext& context,
const IntRect& rect,
Image* image,
bool isEnabled = true) {
return paintMediaButton(context, rect, image, 0, isEnabled);
}
bool MediaControlsPainter::paintMediaMuteButton(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
// The new UI uses "muted" and "not muted" only.
static Image* soundLevel3 =
platformResource("mediaplayerSoundLevel3", "mediaplayerSoundLevel3New");
static Image* soundLevel2 =
platformResource("mediaplayerSoundLevel2", "mediaplayerSoundLevel3New");
static Image* soundLevel1 =
platformResource("mediaplayerSoundLevel1", "mediaplayerSoundLevel3New");
static Image* soundLevel0 =
platformResource("mediaplayerSoundLevel0", "mediaplayerSoundLevel0New");
static Image* soundDisabled =
platformResource("mediaplayerSoundDisabled", "mediaplayerSoundLevel0New");
if (!hasSource(mediaElement) || !mediaElement->hasAudio())
return paintMediaButton(paintInfo.context, rect, soundDisabled, &object,
false);
if (mediaElement->muted() || mediaElement->volume() <= 0)
return paintMediaButton(paintInfo.context, rect, soundLevel0, &object,
true);
if (mediaElement->volume() <= 0.33)
return paintMediaButton(paintInfo.context, rect, soundLevel1, &object,
true);
if (mediaElement->volume() <= 0.66)
return paintMediaButton(paintInfo.context, rect, soundLevel2, &object,
true);
return paintMediaButton(paintInfo.context, rect, soundLevel3, &object, true);
}
bool MediaControlsPainter::paintMediaPlayButton(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaPlay =
platformResource("mediaplayerPlay", "mediaplayerPlayNew");
static Image* mediaPause =
platformResource("mediaplayerPause", "mediaplayerPauseNew");
// For this case, the new UI draws the normal icon, but the entire panel
// grays out.
static Image* mediaPlayDisabled =
platformResource("mediaplayerPlayDisabled", "mediaplayerPlayNew");
if (!hasSource(mediaElement))
return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled, &object,
false);
Image* image =
!object.node()->isMediaControlElement() ||
mediaControlElementType(object.node()) == MediaPlayButton
? mediaPlay
: mediaPause;
return paintMediaButton(paintInfo.context, rect, image, &object, true);
}
bool MediaControlsPainter::paintMediaOverlayPlayButton(
const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
if (!hasSource(mediaElement) || !mediaElement->paused())
return false;
static Image* mediaOverlayPlay =
platformResource("mediaplayerOverlayPlay", "mediaplayerOverlayPlayNew");
IntRect buttonRect(rect);
if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
// Overlay play button covers the entire player, so center and draw a
// smaller button. Center in the entire element.
// TODO(liberato): object.enclosingBox()?
const LayoutBox* box = mediaElement->layoutObject()->enclosingBox();
if (!box)
return false;
int mediaHeight = box->pixelSnappedHeight();
buttonRect.setX(rect.center().x() - mediaOverlayPlayButtonWidthNew / 2);
buttonRect.setY(rect.center().y() - mediaOverlayPlayButtonHeightNew / 2 +
(mediaHeight - rect.height()) / 2);
buttonRect.setWidth(mediaOverlayPlayButtonWidthNew);
buttonRect.setHeight(mediaOverlayPlayButtonHeightNew);
}
return paintMediaButton(paintInfo.context, buttonRect, mediaOverlayPlay);
}
static Image* getMediaSliderThumb() {
static Image* mediaSliderThumb =
platformResource("mediaplayerSliderThumb", "mediaplayerSliderThumbNew");
return mediaSliderThumb;
}
static void paintRoundedSliderBackground(const IntRect& rect,
const ComputedStyle& style,
GraphicsContext& context,
Color sliderBackgroundColor) {
float borderRadius = rect.height() / 2;
FloatSize radii(borderRadius, borderRadius);
context.fillRoundedRect(FloatRoundedRect(rect, radii, radii, radii, radii),
sliderBackgroundColor);
}
static void paintSliderRangeHighlight(const IntRect& rect,
const ComputedStyle& style,
GraphicsContext& context,
int startPosition,
int endPosition,
Color startColor,
Color endColor) {
// Calculate border radius; need to avoid being smaller than half the slider
// height because of https://bugs.webkit.org/show_bug.cgi?id=30143.
float borderRadius = rect.height() / 2.0f;
FloatSize radii(borderRadius, borderRadius);
// Calculate highlight rectangle and edge dimensions.
int startOffset = startPosition;
int endOffset = rect.width() - endPosition;
int rangeWidth = endPosition - startPosition;
if (rangeWidth <= 0)
return;
// Make sure the range width is bigger than border radius at the edges to
// retain rounded corners.
if (startOffset < borderRadius && rangeWidth < borderRadius)
rangeWidth = borderRadius;
if (endOffset < borderRadius && rangeWidth < borderRadius)
rangeWidth = borderRadius;
// Set rectangle to highlight range.
IntRect highlightRect = rect;
highlightRect.move(startOffset, 0);
highlightRect.setWidth(rangeWidth);
// Don't bother drawing an empty area.
if (highlightRect.isEmpty())
return;
// Calculate white-grey gradient.
FloatPoint sliderTopLeft = highlightRect.location();
FloatPoint sliderBottomLeft = sliderTopLeft;
sliderBottomLeft.move(0, highlightRect.height());
RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderBottomLeft);
gradient->addColorStop(0.0, startColor);
gradient->addColorStop(1.0, endColor);
// Fill highlight rectangle with gradient, potentially rounded if on left or
// right edge.
SkPaint gradientPaint(context.fillPaint());
gradient->applyToPaint(gradientPaint, SkMatrix::I());
if (startOffset < borderRadius && endOffset < borderRadius)
context.drawRRect(
FloatRoundedRect(highlightRect, radii, radii, radii, radii),
gradientPaint);
else if (startOffset < borderRadius)
context.drawRRect(FloatRoundedRect(highlightRect, radii, FloatSize(0, 0),
radii, FloatSize(0, 0)),
gradientPaint);
else if (endOffset < borderRadius)
context.drawRRect(FloatRoundedRect(highlightRect, FloatSize(0, 0), radii,
FloatSize(0, 0), radii),
gradientPaint);
else
context.drawRect(highlightRect, gradientPaint);
}
bool MediaControlsPainter::paintMediaSlider(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
GraphicsContext& context = paintInfo.context;
// Should we paint the slider partially transparent?
bool drawUiGrayed = !hasSource(mediaElement) &&
RuntimeEnabledFeatures::newMediaPlaybackUiEnabled();
if (drawUiGrayed)
context.beginLayer(kDisabledAlpha);
paintMediaSliderInternal(object, paintInfo, rect);
if (drawUiGrayed)
context.endLayer();
return true;
}
void MediaControlsPainter::paintMediaSliderInternal(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled();
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return;
const ComputedStyle& style = object.styleRef();
GraphicsContext& context = paintInfo.context;
// Paint the slider bar in the "no data buffered" state.
Color sliderBackgroundColor;
if (!useNewUi)
sliderBackgroundColor = Color(11, 11, 11);
else
sliderBackgroundColor = Color(0xda, 0xda, 0xda);
paintRoundedSliderBackground(rect, style, context, sliderBackgroundColor);
// Draw the buffered range. Since the element may have multiple buffered
// ranges and it'd be distracting/'busy' to show all of them, show only the
// buffered range containing the current play head.
TimeRanges* bufferedTimeRanges = mediaElement->buffered();
float duration = mediaElement->duration();
float currentTime = mediaElement->currentTime();
if (std::isnan(duration) || std::isinf(duration) || !duration ||
std::isnan(currentTime))
return;
for (unsigned i = 0; i < bufferedTimeRanges->length(); ++i) {
float start = bufferedTimeRanges->start(i, ASSERT_NO_EXCEPTION);
float end = bufferedTimeRanges->end(i, ASSERT_NO_EXCEPTION);
// The delta is there to avoid corner cases when buffered
// ranges is out of sync with current time because of
// asynchronous media pipeline and current time caching in
// HTMLMediaElement.
// This is related to https://www.w3.org/Bugs/Public/show_bug.cgi?id=28125
// FIXME: Remove this workaround when WebMediaPlayer
// has an asynchronous pause interface.
if (std::isnan(start) || std::isnan(end) ||
start > currentTime + kCurrentTimeBufferedDelta || end < currentTime)
continue;
int startPosition = int(start * rect.width() / duration);
int currentPosition = int(currentTime * rect.width() / duration);
int endPosition = int(end * rect.width() / duration);
if (!useNewUi) {
// Add half the thumb width proportionally adjusted to the current
// painting position.
int thumbCenter = mediaSliderThumbWidth / 2;
int addWidth = thumbCenter * (1.0 - 2.0 * currentPosition / rect.width());
currentPosition += addWidth;
}
// Draw highlight before current time.
Color startColor;
Color endColor;
if (!useNewUi) {
startColor = Color(195, 195, 195); // white-ish.
endColor = Color(217, 217, 217);
} else {
startColor = endColor = Color(0x42, 0x85, 0xf4); // blue.
}
if (currentPosition > startPosition)
paintSliderRangeHighlight(rect, style, context, startPosition,
currentPosition, startColor, endColor);
// Draw grey-ish highlight after current time.
if (!useNewUi) {
startColor = Color(60, 60, 60);
endColor = Color(76, 76, 76);
} else {
startColor = endColor = Color(0x5a, 0x5a, 0x5a); // dark grey
}
if (endPosition > currentPosition)
paintSliderRangeHighlight(rect, style, context, currentPosition,
endPosition, startColor, endColor);
return;
}
}
void MediaControlsPainter::adjustMediaSliderThumbPaintSize(
const IntRect& rect,
const ComputedStyle& style,
IntRect& rectOut) {
// Adjust the rectangle to be centered, the right size for the image.
// We do this because it's quite hard to get the thumb touch target
// to match. So, we provide the touch target size with
// adjustMediaSliderThumbSize(), and scale it back when we paint.
rectOut = rect;
if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
// ...except for the old UI.
return;
}
float zoomLevel = style.effectiveZoom();
float zoomedPaintWidth = mediaSliderThumbPaintWidthNew * zoomLevel;
float zoomedPaintHeight = mediaSliderThumbPaintHeightNew * zoomLevel;
rectOut.setX(rect.center().x() - zoomedPaintWidth / 2);
rectOut.setY(rect.center().y() - zoomedPaintHeight / 2);
rectOut.setWidth(zoomedPaintWidth);
rectOut.setHeight(zoomedPaintHeight);
}
bool MediaControlsPainter::paintMediaSliderThumb(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
if (!object.node())
return false;
const HTMLMediaElement* mediaElement =
toParentMediaElement(object.node()->ownerShadowHost());
if (!mediaElement)
return false;
if (!hasSource(mediaElement))
return true;
Image* mediaSliderThumb = getMediaSliderThumb();
IntRect paintRect;
const ComputedStyle& style = object.styleRef();
adjustMediaSliderThumbPaintSize(rect, style, paintRect);
return paintMediaButton(paintInfo.context, paintRect, mediaSliderThumb);
}
bool MediaControlsPainter::paintMediaVolumeSlider(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
GraphicsContext& context = paintInfo.context;
const ComputedStyle& style = object.styleRef();
// Paint the slider bar.
Color sliderBackgroundColor;
if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled())
sliderBackgroundColor = Color(11, 11, 11);
else
sliderBackgroundColor = Color(0x5a, 0x5a, 0x5a); // dark grey
paintRoundedSliderBackground(rect, style, context, sliderBackgroundColor);
// Calculate volume position for white background rectangle.
float volume = mediaElement->volume();
if (std::isnan(volume) || volume < 0)
return true;
if (volume > 1)
volume = 1;
if (!hasSource(mediaElement) || !mediaElement->hasAudio() ||
mediaElement->muted())
volume = 0;
// Calculate the position relative to the center of the thumb.
float fillWidth = 0;
if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
if (volume > 0) {
float thumbCenter = mediaVolumeSliderThumbWidth / 2;
float zoomLevel = style.effectiveZoom();
float positionWidth = volume * (rect.width() - (zoomLevel * thumbCenter));
fillWidth = positionWidth + (zoomLevel * thumbCenter / 2);
}
} else {
fillWidth = volume * rect.width();
}
Color startColor = Color(195, 195, 195);
Color endColor = Color(217, 217, 217);
if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled())
startColor = endColor = Color(0x42, 0x85, 0xf4); // blue.
paintSliderRangeHighlight(rect, style, context, 0.0, fillWidth, startColor,
endColor);
return true;
}
bool MediaControlsPainter::paintMediaVolumeSliderThumb(
const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
if (!object.node())
return false;
const HTMLMediaElement* mediaElement =
toParentMediaElement(object.node()->ownerShadowHost());
if (!mediaElement)
return false;
if (!hasSource(mediaElement) || !mediaElement->hasAudio())
return true;
static Image* mediaVolumeSliderThumb = platformResource(
"mediaplayerVolumeSliderThumb", "mediaplayerVolumeSliderThumbNew");
IntRect paintRect;
const ComputedStyle& style = object.styleRef();
adjustMediaSliderThumbPaintSize(rect, style, paintRect);
return paintMediaButton(paintInfo.context, paintRect, mediaVolumeSliderThumb);
}
bool MediaControlsPainter::paintMediaFullscreenButton(
const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
// With the new player UI, we have separate assets for enter / exit
// fullscreen mode.
static Image* mediaEnterFullscreenButton =
platformResource("mediaplayerFullscreen", "mediaplayerEnterFullscreen");
static Image* mediaExitFullscreenButton =
platformResource("mediaplayerFullscreen", "mediaplayerExitFullscreen");
bool isEnabled = hasSource(mediaElement);
if (mediaControlElementType(object.node()) == MediaExitFullscreenButton)
return paintMediaButton(paintInfo.context, rect, mediaExitFullscreenButton,
&object, isEnabled);
return paintMediaButton(paintInfo.context, rect, mediaEnterFullscreenButton,
&object, isEnabled);
}
bool MediaControlsPainter::paintMediaToggleClosedCaptionsButton(
const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaClosedCaptionButton = platformResource(
"mediaplayerClosedCaption", "mediaplayerClosedCaptionNew");
static Image* mediaClosedCaptionButtonDisabled =
platformResource("mediaplayerClosedCaptionDisabled",
"mediaplayerClosedCaptionDisabledNew");
bool isEnabled = mediaElement->hasClosedCaptions();
if (mediaElement->textTracksVisible())
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButton,
&object, isEnabled);
return paintMediaButton(paintInfo.context, rect,
mediaClosedCaptionButtonDisabled, &object, isEnabled);
}
bool MediaControlsPainter::paintMediaCastButton(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaCastOn =
platformResource("mediaplayerCastOn", "mediaplayerCastOnNew");
static Image* mediaCastOff =
platformResource("mediaplayerCastOff", "mediaplayerCastOffNew");
// To ensure that the overlaid cast button is visible when overlaid on pale
// videos we use a different version of it for the overlaid case with a
// semi-opaque background.
static Image* mediaOverlayCastOff = platformResource(
"mediaplayerOverlayCastOff", "mediaplayerOverlayCastOffNew");
bool isEnabled = mediaElement->hasRemoteRoutes();
switch (mediaControlElementType(object.node())) {
case MediaCastOnButton:
return paintMediaButton(paintInfo.context, rect, mediaCastOn, &object,
isEnabled);
case MediaOverlayCastOnButton:
return paintMediaButton(paintInfo.context, rect, mediaCastOn);
case MediaCastOffButton:
return paintMediaButton(paintInfo.context, rect, mediaCastOff, &object,
isEnabled);
case MediaOverlayCastOffButton:
return paintMediaButton(paintInfo.context, rect, mediaOverlayCastOff);
default:
ASSERT_NOT_REACHED();
return false;
}
}
bool MediaControlsPainter::paintMediaTrackSelectionCheckmark(
const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaTrackSelectionCheckmark =
platformResource("mediaplayerTrackSelectionCheckmark",
"mediaplayerTrackSelectionCheckmarkNew");
return paintMediaButton(paintInfo.context, rect,
mediaTrackSelectionCheckmark);
}
bool MediaControlsPainter::paintMediaClosedCaptionsIcon(
const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaClosedCaptionsIcon = platformResource(
"mediaplayerClosedCaptionsIcon", "mediaplayerClosedCaptionsIconNew");
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionsIcon);
}
bool MediaControlsPainter::paintMediaSubtitlesIcon(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaSubtitlesIcon = platformResource(
"mediaplayerSubtitlesIcon", "mediaplayerSubtitlesIconNew");
return paintMediaButton(paintInfo.context, rect, mediaSubtitlesIcon);
}
bool MediaControlsPainter::paintMediaOverflowMenu(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
static Image* mediaOverflowButton =
platformResource("mediaplayerOverflowMenu");
return paintMediaButton(paintInfo.context, rect, mediaOverflowButton, &object,
true);
}
bool MediaControlsPainter::paintMediaDownloadIcon(const LayoutObject& object,
const PaintInfo& paintInfo,
const IntRect& rect) {
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
if (!mediaElement)
return false;
bool isEnabled = hasSource(mediaElement);
static Image* mediaDownloadIcon = platformResource("mediaplayerDownloadIcon");
return paintMediaButton(paintInfo.context, rect, mediaDownloadIcon, &object,
isEnabled);
}
void MediaControlsPainter::adjustMediaSliderThumbSize(ComputedStyle& style) {
static Image* mediaSliderThumb =
platformResource("mediaplayerSliderThumb", "mediaplayerSliderThumbNew");
static Image* mediaVolumeSliderThumb = platformResource(
"mediaplayerVolumeSliderThumb", "mediaplayerVolumeSliderThumbNew");
int width = 0;
int height = 0;
Image* thumbImage = 0;
if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
// Volume and time sliders are the same.
thumbImage = mediaSliderThumb;
width = mediaSliderThumbTouchWidthNew;
height = mediaSliderThumbTouchHeightNew;
} else if (style.appearance() == MediaSliderThumbPart) {
thumbImage = mediaSliderThumb;
width = mediaSliderThumbWidth;
height = mediaSliderThumbHeight;
} else if (style.appearance() == MediaVolumeSliderThumbPart) {
thumbImage = mediaVolumeSliderThumb;
width = mediaVolumeSliderThumbWidth;
height = mediaVolumeSliderThumbHeight;
}
float zoomLevel = style.effectiveZoom();
if (thumbImage) {
style.setWidth(Length(static_cast<int>(width * zoomLevel), Fixed));
style.setHeight(Length(static_cast<int>(height * zoomLevel), Fixed));
}
}
} // namespace blink