/* * 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 #endif namespace WebCore { static const int textFieldBorderSize = 1; static constexpr auto textFieldBorderColorLight = SRGBA { 205, 199, 194 }; static constexpr auto textFieldBorderDisabledColorLight = SRGBA { 205, 199, 194 }; static constexpr auto textFieldBackgroundColorLight = Color::white; static constexpr auto textFieldBackgroundDisabledColorLight = SRGBA { 250, 249, 248 }; static constexpr auto textFieldBorderColorDark = SRGBA { 27, 27, 27 }; static constexpr auto textFieldBorderDisabledColorDark = SRGBA { 27, 27, 27 }; static constexpr auto textFieldBackgroundColorDark = SRGBA { 45, 45, 45 }; static constexpr auto textFieldBackgroundDisabledColorDark = SRGBA { 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 { 205, 199, 194 }; static constexpr auto progressBarBackgroundColorLight = SRGBA { 225, 222, 219 }; static constexpr auto progressBarBorderColorDark = SRGBA { 27, 27, 27 }; static constexpr auto progressBarBackgroundColorDark = SRGBA { 40, 40, 40 }; static const unsigned sliderTrackSize = 6; static const int sliderTrackBorderSize = 1; static constexpr auto sliderTrackBorderColorLight = SRGBA { 205, 199, 194 }; static constexpr auto sliderTrackBackgroundColorLight = SRGBA { 225, 222, 219 }; static constexpr auto sliderTrackBorderColorDark = SRGBA { 27, 27, 27 }; static constexpr auto sliderTrackBackgroundColorDark = SRGBA { 40, 40, 40 }; static const int sliderTrackFocusOffset = 2; static const int sliderThumbSize = 20; static const int sliderThumbBorderSize = 1; static constexpr auto sliderThumbBorderColorLight = SRGBA { 205, 199, 194 }; static constexpr auto sliderThumbBackgroundColorLight = SRGBA { 244, 242, 241 }; static constexpr auto sliderThumbBackgroundHoveredColorLight = SRGBA { 248, 248, 247 }; static constexpr auto sliderThumbBackgroundDisabledColorLight = SRGBA { 250, 249, 248 }; static constexpr auto sliderThumbBorderColorDark = SRGBA { 27, 27, 27 }; static constexpr auto sliderThumbBackgroundColorDark = SRGBA { 52, 52, 52 }; static constexpr auto sliderThumbBackgroundHoveredColorDark = SRGBA { 55, 55, 55 }; static constexpr auto sliderThumbBackgroundDisabledColorDark = SRGBA { 50, 50, 50 }; #if ENABLE(VIDEO) static constexpr auto mediaSliderTrackBackgroundcolor = SRGBA { 77, 77, 77 }; static constexpr auto mediaSliderTrackBufferedColor = SRGBA { 173, 173, 173 }; static constexpr auto mediaSliderTrackActiveColor = SRGBA { 252, 252, 252 }; #endif static constexpr auto buttonTextColorLight = SRGBA { 46, 52, 54 }; static constexpr auto buttonTextDisabledColorLight = SRGBA { 146, 149, 149 }; static constexpr auto buttonTextColorDark = SRGBA { 238, 238, 236 }; static constexpr auto buttonTextDisabledColorDark = SRGBA { 145, 145, 144 }; #if !PLATFORM(GTK) RenderTheme& RenderTheme::singleton() { static MainThreadNeverDestroyed theme; return theme; } #endif bool RenderThemeAdwaita::supportsFocusRing(const RenderStyle& style) const { switch (style.appearance()) { 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) const { return static_cast(Theme::singleton()).activeSelectionBackgroundColor(); } Color RenderThemeAdwaita::platformInactiveSelectionBackgroundColor(OptionSet) const { return static_cast(Theme::singleton()).inactiveSelectionBackgroundColor(); } Color RenderThemeAdwaita::platformActiveSelectionForegroundColor(OptionSet) const { return static_cast(Theme::singleton()).activeSelectionForegroundColor(); } Color RenderThemeAdwaita::platformInactiveSelectionForegroundColor(OptionSet) const { return static_cast(Theme::singleton()).inactiveSelectionForegroundColor(); } Color RenderThemeAdwaita::platformActiveListBoxSelectionBackgroundColor(OptionSet) const { return static_cast(Theme::singleton()).activeSelectionBackgroundColor(); } Color RenderThemeAdwaita::platformInactiveListBoxSelectionBackgroundColor(OptionSet) const { return static_cast(Theme::singleton()).inactiveSelectionBackgroundColor(); } Color RenderThemeAdwaita::platformActiveListBoxSelectionForegroundColor(OptionSet) const { return static_cast(Theme::singleton()).activeSelectionForegroundColor(); } Color RenderThemeAdwaita::platformInactiveListBoxSelectionForegroundColor(OptionSet) const { return static_cast(Theme::singleton()).inactiveSelectionForegroundColor(); } Color RenderThemeAdwaita::platformFocusRingColor(OptionSet options) const { return ThemeAdwaita::focusColor(options.contains(StyleColor::Options::UseDarkAppearance)); } void RenderThemeAdwaita::platformColorsDidChange() { static_cast(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 RenderThemeAdwaita::mediaControlsScripts() { return { StringImpl::createWithoutCopying(mediaControlsAdwaitaJavaScript, sizeof(mediaControlsAdwaitaJavaScript)) }; } #endif Color RenderThemeAdwaita::systemColor(CSSValueID cssValueID, OptionSet options) const { const bool useDarkAppearance = options.contains(StyleColor::Options::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 { 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 { 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 textFieldBackgroundColor; SRGBA textFieldBackgroundDisabledColor; SRGBA textFieldBorderColor; SRGBA 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(renderObject.generatingNode()) && downcast(*(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.appearance() == 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 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()); 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 progressBarBackgroundColor; SRGBA 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(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(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().appearance(); 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 sliderTrackBackgroundColor; SRGBA 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(renderObject.node())) { auto& input = downcast(*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.appearance(); 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().appearance() == SliderThumbHorizontalPart || renderObject.style().appearance() == SliderThumbVerticalPart); SRGBA sliderThumbBackgroundColor; SRGBA sliderThumbBackgroundHoveredColor; SRGBA sliderThumbBackgroundDisabledColor; SRGBA 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 parentMediaElement(const Node* node) { if (!node) return nullptr; RefPtr mediaNode = node->shadowHost(); if (!mediaNode) mediaNode = const_cast(node); if (!is(*mediaNode)) return nullptr; return downcast(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 = 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