blob: 2d74c09ef625ef4b9f3744101457431a15017e77 [file] [log] [blame]
/*
* Copyright (C) 2014, 2020 Igalia S.L.
*
* 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. AND ITS CONTRIBUTORS ``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 ITS 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 "RenderThemeAdwaita.h"
#include "Color.h"
#include "FloatRoundedRect.h"
#include "GraphicsContext.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "MediaControlTextTrackContainerElement.h"
#include "PaintInfo.h"
#include "RenderBox.h"
#include "RenderObject.h"
#include "RenderProgress.h"
#include "RenderStyle.h"
#include "ThemeAdwaita.h"
#include "TimeRanges.h"
#include "UserAgentScripts.h"
#include "UserAgentStyleSheets.h"
#if PLATFORM(GTK)
#include <gtk/gtk.h>
#endif
namespace WebCore {
static const int textFieldBorderSize = 1;
static constexpr auto textFieldBorderColorLight = SRGBA<uint8_t> { 205, 199, 194 };
static constexpr auto textFieldBorderDisabledColorLight = SRGBA<uint8_t> { 205, 199, 194 };
static constexpr auto textFieldBackgroundColorLight = Color::white;
static constexpr auto textFieldBackgroundDisabledColorLight = SRGBA<uint8_t> { 250, 249, 248 };
static constexpr auto textFieldBorderColorDark = SRGBA<uint8_t> { 27, 27, 27 };
static constexpr auto textFieldBorderDisabledColorDark = SRGBA<uint8_t> { 27, 27, 27 };
static constexpr auto textFieldBackgroundColorDark = SRGBA<uint8_t> { 45, 45, 45 };
static constexpr auto textFieldBackgroundDisabledColorDark = SRGBA<uint8_t> { 50, 50, 50 };
static const unsigned menuListButtonArrowSize = 16;
static const int menuListButtonFocusOffset = -3;
static const unsigned menuListButtonPadding = 5;
static const int menuListButtonBorderSize = 1; // Keep in sync with buttonBorderSize in ThemeAdwaita.
static const unsigned progressActivityBlocks = 5;
static const unsigned progressAnimationFrameCount = 75;
static const Seconds progressAnimationFrameRate = 33_ms; // 30fps.
static const unsigned progressBarSize = 6;
static constexpr auto progressBarBorderColorLight = SRGBA<uint8_t> { 205, 199, 194 };
static constexpr auto progressBarBackgroundColorLight = SRGBA<uint8_t> { 225, 222, 219 };
static constexpr auto progressBarBorderColorDark = SRGBA<uint8_t> { 27, 27, 27 };
static constexpr auto progressBarBackgroundColorDark = SRGBA<uint8_t> { 40, 40, 40 };
static const unsigned sliderTrackSize = 6;
static const int sliderTrackBorderSize = 1;
static constexpr auto sliderTrackBorderColorLight = SRGBA<uint8_t> { 205, 199, 194 };
static constexpr auto sliderTrackBackgroundColorLight = SRGBA<uint8_t> { 225, 222, 219 };
static constexpr auto sliderTrackBorderColorDark = SRGBA<uint8_t> { 27, 27, 27 };
static constexpr auto sliderTrackBackgroundColorDark = SRGBA<uint8_t> { 40, 40, 40 };
static const int sliderTrackFocusOffset = 2;
static const int sliderThumbSize = 20;
static const int sliderThumbBorderSize = 1;
static constexpr auto sliderThumbBorderColorLight = SRGBA<uint8_t> { 205, 199, 194 };
static constexpr auto sliderThumbBackgroundColorLight = SRGBA<uint8_t> { 244, 242, 241 };
static constexpr auto sliderThumbBackgroundHoveredColorLight = SRGBA<uint8_t> { 248, 248, 247 };
static constexpr auto sliderThumbBackgroundDisabledColorLight = SRGBA<uint8_t> { 250, 249, 248 };
static constexpr auto sliderThumbBorderColorDark = SRGBA<uint8_t> { 27, 27, 27 };
static constexpr auto sliderThumbBackgroundColorDark = SRGBA<uint8_t> { 52, 52, 52 };
static constexpr auto sliderThumbBackgroundHoveredColorDark = SRGBA<uint8_t> { 55, 55, 55 };
static constexpr auto sliderThumbBackgroundDisabledColorDark = SRGBA<uint8_t> { 50, 50, 50 };
#if ENABLE(VIDEO)
static constexpr auto mediaSliderTrackBackgroundcolor = SRGBA<uint8_t> { 77, 77, 77 };
static constexpr auto mediaSliderTrackBufferedColor = SRGBA<uint8_t> { 173, 173, 173 };
static constexpr auto mediaSliderTrackActiveColor = SRGBA<uint8_t> { 252, 252, 252 };
#endif
static constexpr auto buttonTextColorLight = SRGBA<uint8_t> { 46, 52, 54 };
static constexpr auto buttonTextDisabledColorLight = SRGBA<uint8_t> { 146, 149, 149 };
static constexpr auto buttonTextColorDark = SRGBA<uint8_t> { 238, 238, 236 };
static constexpr auto buttonTextDisabledColorDark = SRGBA<uint8_t> { 145, 145, 144 };
#if !PLATFORM(GTK)
RenderTheme& RenderTheme::singleton()
{
static MainThreadNeverDestroyed<RenderThemeAdwaita> theme;
return theme;
}
#endif
bool RenderThemeAdwaita::supportsFocusRing(const RenderStyle& style) const
{
switch (style.effectiveAppearance()) {
case PushButtonPart:
case ButtonPart:
case TextFieldPart:
case TextAreaPart:
case SearchFieldPart:
case MenulistPart:
case RadioPart:
case CheckboxPart:
case SliderHorizontalPart:
case SliderVerticalPart:
return true;
default:
break;
}
return false;
}
bool RenderThemeAdwaita::shouldHaveCapsLockIndicator(const HTMLInputElement& element) const
{
return element.isPasswordField();
}
Color RenderThemeAdwaita::platformActiveSelectionBackgroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).activeSelectionBackgroundColor();
}
Color RenderThemeAdwaita::platformInactiveSelectionBackgroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).inactiveSelectionBackgroundColor();
}
Color RenderThemeAdwaita::platformActiveSelectionForegroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).activeSelectionForegroundColor();
}
Color RenderThemeAdwaita::platformInactiveSelectionForegroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).inactiveSelectionForegroundColor();
}
Color RenderThemeAdwaita::platformActiveListBoxSelectionBackgroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).activeSelectionBackgroundColor();
}
Color RenderThemeAdwaita::platformInactiveListBoxSelectionBackgroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).inactiveSelectionBackgroundColor();
}
Color RenderThemeAdwaita::platformActiveListBoxSelectionForegroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).activeSelectionForegroundColor();
}
Color RenderThemeAdwaita::platformInactiveListBoxSelectionForegroundColor(OptionSet<StyleColorOptions>) const
{
return static_cast<ThemeAdwaita&>(Theme::singleton()).inactiveSelectionForegroundColor();
}
Color RenderThemeAdwaita::platformFocusRingColor(OptionSet<StyleColorOptions> options) const
{
return ThemeAdwaita::focusColor(options.contains(StyleColorOptions::UseDarkAppearance));
}
void RenderThemeAdwaita::platformColorsDidChange()
{
static_cast<ThemeAdwaita&>(Theme::singleton()).platformColorsDidChange();
RenderTheme::platformColorsDidChange();
}
String RenderThemeAdwaita::extraDefaultStyleSheet()
{
return StringImpl::createWithoutCopying(themeAdwaitaUserAgentStyleSheet, sizeof(themeAdwaitaUserAgentStyleSheet));
}
#if ENABLE(VIDEO)
String RenderThemeAdwaita::extraMediaControlsStyleSheet()
{
return StringImpl::createWithoutCopying(mediaControlsAdwaitaUserAgentStyleSheet, sizeof(mediaControlsAdwaitaUserAgentStyleSheet));
}
Vector<String, 2> RenderThemeAdwaita::mediaControlsScripts()
{
return { StringImpl::createWithoutCopying(mediaControlsAdwaitaJavaScript, sizeof(mediaControlsAdwaitaJavaScript)) };
}
#endif
Color RenderThemeAdwaita::systemColor(CSSValueID cssValueID, OptionSet<StyleColorOptions> options) const
{
const bool useDarkAppearance = options.contains(StyleColorOptions::UseDarkAppearance);
switch (cssValueID) {
case CSSValueActivecaption:
case CSSValueActivebuttontext:
case CSSValueButtontext:
return useDarkAppearance ? buttonTextColorDark : buttonTextColorLight;
case CSSValueGraytext:
return useDarkAppearance ? buttonTextDisabledColorDark : buttonTextDisabledColorLight;
case CSSValueCanvas:
case CSSValueField:
case CSSValueWebkitControlBackground:
return useDarkAppearance ? textFieldBackgroundColorDark : textFieldBackgroundColorLight;
case CSSValueWindow:
return useDarkAppearance ? SRGBA<uint8_t> { 30, 30, 30 } : Color::white;
case CSSValueCanvastext:
case CSSValueCaptiontext:
case CSSValueFieldtext:
case CSSValueInactivecaptiontext:
case CSSValueInfotext:
case CSSValueText:
case CSSValueWindowtext:
return useDarkAppearance ? Color::white : Color::black;
case CSSValueInactiveborder:
case CSSValueInactivecaption:
return useDarkAppearance ? Color::black : Color::white;
case CSSValueWebkitFocusRingColor:
case CSSValueActiveborder:
case CSSValueHighlight:
// Hardcoded to avoid exposing a user appearance preference to the web for fingerprinting.
return SRGBA<uint8_t> { 52, 132, 228 };
case CSSValueHighlighttext:
return Color::white;
default:
return RenderTheme::systemColor(cssValueID, options);
}
}
bool RenderThemeAdwaita::paintTextField(const RenderObject& renderObject, const PaintInfo& paintInfo, const FloatRect& rect)
{
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
SRGBA<uint8_t> textFieldBackgroundColor;
SRGBA<uint8_t> textFieldBackgroundDisabledColor;
SRGBA<uint8_t> textFieldBorderColor;
SRGBA<uint8_t> textFieldBorderDisabledColor;
if (renderObject.useDarkAppearance()) {
textFieldBackgroundColor = textFieldBackgroundColorDark;
textFieldBackgroundDisabledColor = textFieldBackgroundDisabledColorDark;
textFieldBorderColor= textFieldBorderColorDark;
textFieldBorderDisabledColor = textFieldBorderDisabledColorDark;
} else {
textFieldBackgroundColor = textFieldBackgroundColorLight;
textFieldBackgroundDisabledColor = textFieldBackgroundDisabledColorLight;
textFieldBorderColor = textFieldBorderColorLight;
textFieldBorderDisabledColor = textFieldBorderDisabledColorLight;
}
int borderSize = textFieldBorderSize;
if (isEnabled(renderObject) && !isReadOnlyControl(renderObject) && isFocused(renderObject))
borderSize *= 2;
FloatRect fieldRect = rect;
FloatSize corner(5, 5);
Path path;
path.addRoundedRect(fieldRect, corner);
fieldRect.inflate(-borderSize);
corner.expand(-borderSize, -borderSize);
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::EvenOdd);
if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
graphicsContext.setFillColor(textFieldBorderDisabledColor);
else if (isFocused(renderObject))
graphicsContext.setFillColor(activeSelectionBackgroundColor({ }));
else
graphicsContext.setFillColor(textFieldBorderColor);
graphicsContext.fillPath(path);
path.clear();
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::NonZero);
if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
graphicsContext.setFillColor(textFieldBackgroundDisabledColor);
else
graphicsContext.setFillColor(textFieldBackgroundColor);
graphicsContext.fillPath(path);
#if ENABLE(DATALIST_ELEMENT)
if (is<HTMLInputElement>(renderObject.generatingNode()) && downcast<HTMLInputElement>(*(renderObject.generatingNode())).list()) {
FloatRect arrowRect = rect;
if (renderObject.style().direction() == TextDirection::LTR)
arrowRect.move(arrowRect.width() - (menuListButtonArrowSize + textFieldBorderSize * 2), (arrowRect.height() / 2.) - (menuListButtonArrowSize / 2.));
else
fieldRect.move(textFieldBorderSize * 2, (arrowRect.height() / 2.) - (menuListButtonArrowSize / 2.));
arrowRect.setWidth(menuListButtonArrowSize);
arrowRect.setHeight(menuListButtonArrowSize);
{
GraphicsContextStateSaver arrowStateSaver(graphicsContext);
graphicsContext.translate(arrowRect.x(), arrowRect.y());
ThemeAdwaita::paintArrow(graphicsContext, ThemeAdwaita::ArrowDirection::Down, renderObject.useDarkAppearance());
}
}
#endif
return false;
}
void RenderThemeAdwaita::adjustTextFieldStyle(RenderStyle& style, const Element*) const
{
if (!style.hasExplicitlySetBorderRadius())
style.setBorderRadius(IntSize(5, 5));
}
bool RenderThemeAdwaita::paintTextArea(const RenderObject& renderObject, const PaintInfo& paintInfo, const FloatRect& rect)
{
return paintTextField(renderObject, paintInfo, rect);
}
void RenderThemeAdwaita::adjustTextAreaStyle(RenderStyle& style, const Element* element) const
{
adjustTextFieldStyle(style, element);
}
bool RenderThemeAdwaita::paintSearchField(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
{
return paintTextField(renderObject, paintInfo, rect);
}
void RenderThemeAdwaita::adjustSearchFieldStyle(RenderStyle& style, const Element* element) const
{
adjustTextFieldStyle(style, element);
}
void RenderThemeAdwaita::adjustMenuListStyle(RenderStyle& style, const Element*) const
{
style.setLineHeight(RenderStyle::initialLineHeight());
}
void RenderThemeAdwaita::adjustMenuListButtonStyle(RenderStyle& style, const Element* element) const
{
adjustMenuListStyle(style, element);
}
LengthBox RenderThemeAdwaita::popupInternalPaddingBox(const RenderStyle& style, const Settings&) const
{
if (style.effectiveAppearance() == NoControlPart)
return { };
int leftPadding = menuListButtonPadding + (style.direction() == TextDirection::RTL ? menuListButtonArrowSize : 0);
int rightPadding = menuListButtonPadding + (style.direction() == TextDirection::LTR ? menuListButtonArrowSize : 0);
return { menuListButtonPadding, rightPadding, menuListButtonPadding, leftPadding };
}
bool RenderThemeAdwaita::paintMenuList(const RenderObject& renderObject, const PaintInfo& paintInfo, const FloatRect& rect)
{
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
OptionSet<ControlStates::States> states;
if (isEnabled(renderObject))
states.add(ControlStates::States::Enabled);
if (isPressed(renderObject))
states.add(ControlStates::States::Pressed);
if (isHovered(renderObject))
states.add(ControlStates::States::Hovered);
ControlStates controlStates(states);
Theme::singleton().paint(ButtonPart, controlStates, graphicsContext, rect, 1., nullptr, 1., 1., false, renderObject.useDarkAppearance(), renderObject.style().effectiveAccentColor());
FloatRect fieldRect = rect;
fieldRect.inflate(menuListButtonBorderSize);
if (renderObject.style().direction() == TextDirection::LTR)
fieldRect.move(fieldRect.width() - (menuListButtonArrowSize + menuListButtonPadding), (fieldRect.height() / 2.) - (menuListButtonArrowSize / 2));
else
fieldRect.move(menuListButtonPadding, (fieldRect.height() / 2.) - (menuListButtonArrowSize / 2));
fieldRect.setWidth(menuListButtonArrowSize);
fieldRect.setHeight(menuListButtonArrowSize);
{
GraphicsContextStateSaver arrowStateSaver(graphicsContext);
graphicsContext.translate(fieldRect.x(), fieldRect.y());
ThemeAdwaita::paintArrow(graphicsContext, ThemeAdwaita::ArrowDirection::Down, renderObject.useDarkAppearance());
}
if (isFocused(renderObject))
ThemeAdwaita::paintFocus(graphicsContext, rect, menuListButtonFocusOffset, renderObject.useDarkAppearance());
return false;
}
void RenderThemeAdwaita::paintMenuListButtonDecorations(const RenderBox& renderObject, const PaintInfo& paintInfo, const FloatRect& rect)
{
paintMenuList(renderObject, paintInfo, rect);
}
Seconds RenderThemeAdwaita::animationRepeatIntervalForProgressBar(const RenderProgress&) const
{
return progressAnimationFrameRate;
}
Seconds RenderThemeAdwaita::animationDurationForProgressBar(const RenderProgress&) const
{
return progressAnimationFrameRate * progressAnimationFrameCount;
}
IntRect RenderThemeAdwaita::progressBarRectForBounds(const RenderObject&, const IntRect& bounds) const
{
return { bounds.x(), bounds.y(), bounds.width(), progressBarSize };
}
bool RenderThemeAdwaita::paintProgressBar(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
{
if (!renderObject.isProgress())
return true;
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
SRGBA<uint8_t> progressBarBackgroundColor;
SRGBA<uint8_t> progressBarBorderColor;
if (renderObject.useDarkAppearance()) {
progressBarBackgroundColor = progressBarBackgroundColorDark;
progressBarBorderColor = progressBarBorderColorDark;
} else {
progressBarBackgroundColor = progressBarBackgroundColorLight;
progressBarBorderColor = progressBarBorderColorLight;
}
FloatRect fieldRect = rect;
FloatSize corner(3, 3);
Path path;
path.addRoundedRect(fieldRect, corner);
fieldRect.inflate(-1);
corner.expand(-1, -1);
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::EvenOdd);
graphicsContext.setFillColor(progressBarBorderColor);
graphicsContext.fillPath(path);
path.clear();
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::NonZero);
graphicsContext.setFillColor(progressBarBackgroundColor);
graphicsContext.fillPath(path);
path.clear();
fieldRect = rect;
const auto& renderProgress = downcast<RenderProgress>(renderObject);
if (renderProgress.isDeterminate()) {
auto progressWidth = fieldRect.width() * renderProgress.position();
if (renderObject.style().direction() == TextDirection::RTL)
fieldRect.move(fieldRect.width() - progressWidth, 0);
fieldRect.setWidth(progressWidth);
} else {
double animationProgress = renderProgress.animationProgress();
// Never let the progress rect shrink smaller than 2 pixels.
fieldRect.setWidth(std::max<float>(2, fieldRect.width() / progressActivityBlocks));
auto movableWidth = rect.width() - fieldRect.width();
// We want the first 0.5 units of the animation progress to represent the
// forward motion and the second 0.5 units to represent the backward motion,
// thus we multiply by two here to get the full sweep of the progress bar with
// each direction.
if (animationProgress < 0.5)
fieldRect.move(animationProgress * 2 * movableWidth, 0);
else
fieldRect.move((1.0 - animationProgress) * 2 * movableWidth, 0);
}
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::NonZero);
graphicsContext.setFillColor(activeSelectionBackgroundColor({ }));
graphicsContext.fillPath(path);
return false;
}
bool RenderThemeAdwaita::paintSliderTrack(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
{
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
ControlPart part = renderObject.style().effectiveAppearance();
ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart);
FloatRect fieldRect = rect;
if (part == SliderHorizontalPart) {
fieldRect.move(0, rect.height() / 2 - (sliderTrackSize / 2));
fieldRect.setHeight(6);
} else {
fieldRect.move(rect.width() / 2 - (sliderTrackSize / 2), 0);
fieldRect.setWidth(6);
}
SRGBA<uint8_t> sliderTrackBackgroundColor;
SRGBA<uint8_t> sliderTrackBorderColor;
if (renderObject.useDarkAppearance()) {
sliderTrackBackgroundColor = sliderTrackBackgroundColorDark;
sliderTrackBorderColor = sliderTrackBorderColorDark;
} else {
sliderTrackBackgroundColor = sliderTrackBackgroundColorLight;
sliderTrackBorderColor = sliderTrackBorderColorLight;
}
FloatSize corner(3, 3);
Path path;
path.addRoundedRect(fieldRect, corner);
fieldRect.inflate(-sliderTrackBorderSize);
corner.expand(-sliderTrackBorderSize, -sliderTrackBorderSize);
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::EvenOdd);
graphicsContext.setFillColor(sliderTrackBorderColor);
graphicsContext.fillPath(path);
path.clear();
path.addRoundedRect(fieldRect, corner);
graphicsContext.setFillRule(WindRule::NonZero);
graphicsContext.setFillColor(sliderTrackBackgroundColor);
graphicsContext.fillPath(path);
path.clear();
fieldRect.inflate(sliderTrackBorderSize);
LayoutPoint thumbLocation;
if (is<HTMLInputElement>(renderObject.node())) {
auto& input = downcast<HTMLInputElement>(*renderObject.node());
if (auto* element = input.sliderThumbElement())
thumbLocation = element->renderBox()->location();
}
FloatRect rangeRect = fieldRect;
FloatRoundedRect::Radii corners;
if (part == SliderHorizontalPart) {
if (renderObject.style().direction() == TextDirection::RTL) {
rangeRect.move(thumbLocation.x(), 0);
rangeRect.setWidth(rangeRect.width() - thumbLocation.x());
corners.setTopRight(corner);
corners.setBottomRight(corner);
} else {
rangeRect.setWidth(thumbLocation.x());
corners.setTopLeft(corner);
corners.setBottomLeft(corner);
}
} else {
rangeRect.setHeight(thumbLocation.y());
corners.setTopLeft(corner);
corners.setTopRight(corner);
}
path.addRoundedRect(FloatRoundedRect(rangeRect, corners));
graphicsContext.setFillRule(WindRule::NonZero);
graphicsContext.setFillColor(activeSelectionBackgroundColor({ }));
graphicsContext.fillPath(path);
#if ENABLE(DATALIST_ELEMENT)
paintSliderTicks(renderObject, paintInfo, rect);
#endif
if (isFocused(renderObject))
ThemeAdwaita::paintFocus(graphicsContext, fieldRect, sliderTrackFocusOffset, renderObject.useDarkAppearance());
return false;
}
void RenderThemeAdwaita::adjustSliderThumbSize(RenderStyle& style, const Element*) const
{
ControlPart part = style.effectiveAppearance();
if (part != SliderThumbHorizontalPart && part != SliderThumbVerticalPart)
return;
style.setWidth(Length(sliderThumbSize, LengthType::Fixed));
style.setHeight(Length(sliderThumbSize, LengthType::Fixed));
}
bool RenderThemeAdwaita::paintSliderThumb(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
{
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
ASSERT(renderObject.style().effectiveAppearance() == SliderThumbHorizontalPart || renderObject.style().effectiveAppearance() == SliderThumbVerticalPart);
SRGBA<uint8_t> sliderThumbBackgroundColor;
SRGBA<uint8_t> sliderThumbBackgroundHoveredColor;
SRGBA<uint8_t> sliderThumbBackgroundDisabledColor;
SRGBA<uint8_t> sliderThumbBorderColor;
if (renderObject.useDarkAppearance()) {
sliderThumbBackgroundColor = sliderThumbBackgroundColorDark;
sliderThumbBackgroundHoveredColor = sliderThumbBackgroundHoveredColorDark;
sliderThumbBackgroundDisabledColor = sliderThumbBackgroundDisabledColorDark;
sliderThumbBorderColor = sliderThumbBorderColorDark;
} else {
sliderThumbBackgroundColor = sliderThumbBackgroundColorLight;
sliderThumbBackgroundHoveredColor = sliderThumbBackgroundHoveredColorLight;
sliderThumbBackgroundDisabledColor = sliderThumbBackgroundDisabledColorLight;
sliderThumbBorderColor = sliderThumbBorderColorLight;
}
FloatRect fieldRect = rect;
Path path;
path.addEllipse(fieldRect);
fieldRect.inflate(-sliderThumbBorderSize);
path.addEllipse(fieldRect);
graphicsContext.setFillRule(WindRule::EvenOdd);
if (isEnabled(renderObject) && isPressed(renderObject))
graphicsContext.setFillColor(activeSelectionBackgroundColor({ }));
else
graphicsContext.setFillColor(sliderThumbBorderColor);
graphicsContext.fillPath(path);
path.clear();
path.addEllipse(fieldRect);
graphicsContext.setFillRule(WindRule::NonZero);
if (!isEnabled(renderObject))
graphicsContext.setFillColor(sliderThumbBackgroundDisabledColor);
else if (isHovered(renderObject))
graphicsContext.setFillColor(sliderThumbBackgroundHoveredColor);
else
graphicsContext.setFillColor(sliderThumbBackgroundColor);
graphicsContext.fillPath(path);
return false;
}
#if ENABLE(VIDEO)
static RefPtr<HTMLMediaElement> parentMediaElement(const Node* node)
{
if (!node)
return nullptr;
RefPtr<Node> mediaNode = node->shadowHost();
if (!mediaNode)
mediaNode = const_cast<Node*>(node);
if (!is<HTMLMediaElement>(*mediaNode))
return nullptr;
return downcast<HTMLMediaElement>(mediaNode.get());
}
bool RenderThemeAdwaita::paintMediaSliderTrack(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
{
auto mediaElement = parentMediaElement(renderObject.node());
if (!mediaElement)
return false;
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
FloatRect trackRect = rect;
FloatSize corner(2, 2);
Path path;
path.addRoundedRect(trackRect, corner);
graphicsContext.setFillColor(mediaSliderTrackBackgroundcolor);
graphicsContext.fillPath(path);
path.clear();
graphicsContext.setFillColor(mediaSliderTrackBufferedColor);
float mediaDuration = mediaElement->duration();
RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
for (unsigned index = 0; index < timeRanges->length(); ++index) {
float start = timeRanges->start(index).releaseReturnValue();
float end = timeRanges->end(index).releaseReturnValue();
float startRatio = start / mediaDuration;
float lengthRatio = (end - start) / mediaDuration;
if (!lengthRatio)
continue;
FloatRect rangeRect = rect;
rangeRect.setWidth(lengthRatio * rect.width());
if (index)
rangeRect.move(startRatio * rect.width(), 0);
path.addRoundedRect(rangeRect, corner);
graphicsContext.fillPath(path);
path.clear();
}
FloatRect playedRect = rect;
playedRect.setWidth((mediaElement->currentTime() / mediaDuration) * rect.width());
graphicsContext.setFillColor(mediaSliderTrackActiveColor);
path.addRoundedRect(playedRect, corner);
graphicsContext.fillPath(path);
return false;
}
bool RenderThemeAdwaita::paintMediaVolumeSliderTrack(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
{
auto mediaElement = parentMediaElement(renderObject.node());
if (!mediaElement)
return false;
auto& graphicsContext = paintInfo.context();
GraphicsContextStateSaver stateSaver(graphicsContext);
FloatRect trackRect = rect;
FloatSize corner(2, 2);
Path path;
path.addRoundedRect(trackRect, corner);
graphicsContext.setFillColor(mediaSliderTrackBackgroundcolor);
graphicsContext.fillPath(path);
path.clear();
float volume = mediaElement->muted() ? 0.0f : mediaElement->volume();
if (volume) {
FloatRect volumeRect = rect;
volumeRect.setHeight(volumeRect.height() * volume);
volumeRect.move(0, rect.height() - volumeRect.height());
path.addRoundedRect(volumeRect, corner);
graphicsContext.setFillColor(mediaSliderTrackActiveColor);
graphicsContext.fillPath(path);
}
return false;
}
#endif // ENABLE(VIDEO)
#if ENABLE(DATALIST_ELEMENT)
IntSize RenderThemeAdwaita::sliderTickSize() const
{
return { 1, 7 };
}
int RenderThemeAdwaita::sliderTickOffsetFromTrackCenter() const
{
return -16;
}
void RenderThemeAdwaita::adjustListButtonStyle(RenderStyle& style, const Element*) const
{
// Add a margin to place the button at end of the input field.
if (style.isLeftToRightDirection())
style.setMarginRight(Length(-2, LengthType::Fixed));
else
style.setMarginLeft(Length(-2, LengthType::Fixed));
}
#endif // ENABLE(DATALIST_ELEMENT)
#if PLATFORM(GTK)
Seconds RenderThemeAdwaita::caretBlinkInterval() const
{
gboolean shouldBlink;
gint time;
g_object_get(gtk_settings_get_default(), "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, nullptr);
return shouldBlink ? 500_us * time : 0_s;
}
#endif
} // namespace WebCore