| /* |
| * 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 |
| |
| #include <wtf/text/Base64.h> |
| |
| namespace WebCore { |
| |
| static const double disabledOpacity = 0.5; // Keep in sync with disabledOpacity in ThemeAdwaita. |
| static const int textFieldBorderSize = 1; |
| static constexpr auto textFieldBorderColorLight = SRGBA<uint8_t> { 0, 0, 0, 50 }; |
| static constexpr auto textFieldBackgroundColorLight = Color::white; |
| |
| static constexpr auto textFieldBorderColorDark = SRGBA<uint8_t> { 255, 255, 255, 50 }; |
| static constexpr auto textFieldBackgroundColorDark = SRGBA<uint8_t> { 45, 45, 45 }; |
| |
| 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 progressBarBackgroundColorLight = SRGBA<uint8_t> { 0, 0, 0, 40 }; |
| static constexpr auto progressBarBackgroundColorDark = SRGBA<uint8_t> { 255, 255, 255, 30 }; |
| static const unsigned sliderTrackSize = 6; |
| static constexpr auto sliderTrackBackgroundColorLight = SRGBA<uint8_t> { 0, 0, 0, 40 }; |
| static constexpr auto sliderTrackBackgroundColorDark = SRGBA<uint8_t> { 255, 255, 255, 30 }; |
| static const int sliderTrackFocusOffset = 2; |
| static const int sliderThumbSize = 20; |
| static const int sliderThumbBorderSize = 1; |
| static constexpr auto sliderThumbBorderColorLight = SRGBA<uint8_t> { 0, 0, 0, 50 }; |
| static constexpr auto sliderThumbBackgroundColorLight = Color::white; |
| static constexpr auto sliderThumbBackgroundHoveredColorLight = SRGBA<uint8_t> { 244, 244, 244 }; |
| static constexpr auto sliderThumbBackgroundDisabledColorLight = SRGBA<uint8_t> { 244, 244, 244 }; |
| |
| static constexpr auto sliderThumbBorderColorDark = SRGBA<uint8_t> { 0, 0, 0, 50 }; |
| static constexpr auto sliderThumbBackgroundColorDark = SRGBA<uint8_t> { 210, 210, 210 }; |
| static constexpr auto sliderThumbBackgroundHoveredColorDark = SRGBA<uint8_t> { 230, 230, 230 }; |
| static constexpr auto sliderThumbBackgroundDisabledColorDark = SRGBA<uint8_t> { 150, 150, 150 }; |
| |
| #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> { 0, 0, 0, 204 }; |
| static constexpr auto buttonTextDisabledColorLight = SRGBA<uint8_t> { 0, 0, 0, 102 }; |
| static constexpr auto buttonTextColorDark = SRGBA<uint8_t> { 255, 255, 255 }; |
| static constexpr auto buttonTextDisabledColorDark = SRGBA<uint8_t> { 255, 255, 255, 127 }; |
| |
| static inline Color getSystemAccentColor() |
| { |
| return static_cast<ThemeAdwaita&>(Theme::singleton()).accentColor(); |
| } |
| |
| static inline Color getAccentColor(const RenderObject& renderObject) |
| { |
| auto accentColor = renderObject.style().effectiveAccentColor(); |
| if (accentColor.isValid()) |
| return accentColor; |
| |
| return getSystemAccentColor(); |
| } |
| |
| #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 getSystemAccentColor().colorWithAlphaMultipliedBy(0.3); |
| } |
| |
| Color RenderThemeAdwaita::platformInactiveSelectionBackgroundColor(OptionSet<StyleColorOptions> options) const |
| { |
| if (options.contains(StyleColorOptions::UseDarkAppearance)) |
| return SRGBA<uint8_t> { 255, 255, 255, 25 }; |
| |
| return SRGBA<uint8_t> { 0, 0, 0, 25 }; |
| } |
| |
| Color RenderThemeAdwaita::platformActiveSelectionForegroundColor(OptionSet<StyleColorOptions>) const |
| { |
| return { }; |
| } |
| |
| Color RenderThemeAdwaita::platformInactiveSelectionForegroundColor(OptionSet<StyleColorOptions>) const |
| { |
| return { }; |
| } |
| |
| Color RenderThemeAdwaita::platformActiveListBoxSelectionBackgroundColor(OptionSet<StyleColorOptions> options) const |
| { |
| return platformActiveListBoxSelectionForegroundColor(options).colorWithAlpha(0.15); |
| } |
| |
| Color RenderThemeAdwaita::platformInactiveListBoxSelectionBackgroundColor(OptionSet<StyleColorOptions> options) const |
| { |
| return platformInactiveListBoxSelectionForegroundColor(options).colorWithAlpha(0.15); |
| } |
| |
| Color RenderThemeAdwaita::platformActiveListBoxSelectionForegroundColor(OptionSet<StyleColorOptions> options) const |
| { |
| return options.contains(StyleColorOptions::UseDarkAppearance) ? Color::white : Color::black; |
| } |
| |
| Color RenderThemeAdwaita::platformInactiveListBoxSelectionForegroundColor(OptionSet<StyleColorOptions> options) const |
| { |
| return platformActiveListBoxSelectionForegroundColor(options); |
| } |
| |
| 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) |
| |
| Vector<String, 2> RenderThemeAdwaita::mediaControlsScripts() |
| { |
| #if ENABLE(MODERN_MEDIA_CONTROLS) |
| return { StringImpl::createWithoutCopying(ModernMediaControlsJavaScript, sizeof(ModernMediaControlsJavaScript)) }; |
| #else |
| return { }; |
| #endif |
| } |
| |
| String RenderThemeAdwaita::mediaControlsStyleSheet() |
| { |
| #if ENABLE(MODERN_MEDIA_CONTROLS) |
| if (m_mediaControlsStyleSheet.isEmpty()) |
| m_mediaControlsStyleSheet = StringImpl::createWithoutCopying(ModernMediaControlsUserAgentStyleSheet, sizeof(ModernMediaControlsUserAgentStyleSheet)); |
| return m_mediaControlsStyleSheet; |
| #else |
| return emptyString(); |
| #endif |
| } |
| |
| #if ENABLE(MODERN_MEDIA_CONTROLS) |
| |
| String RenderThemeAdwaita::mediaControlsBase64StringForIconNameAndType(const String& iconName, const String& iconType) |
| { |
| auto path = makeString("/org/webkit/media-controls/", iconName, '.', iconType); |
| auto data = adoptGRef(g_resources_lookup_data(path.latin1().data(), G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr)); |
| if (!data) |
| return emptyString(); |
| return base64EncodeToString(g_bytes_get_data(data.get(), nullptr), g_bytes_get_size(data.get())); |
| } |
| |
| String RenderThemeAdwaita::mediaControlsFormattedStringForDuration(double durationInSeconds) |
| { |
| // FIXME: Format this somehow, maybe through GDateTime? |
| return makeString(durationInSeconds); |
| } |
| #endif // ENABLE(MODERN_MEDIA_CONTROLS) |
| #endif // ENABLE(VIDEO) |
| |
| 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> textFieldBorderColor; |
| |
| if (renderObject.useDarkAppearance()) { |
| textFieldBackgroundColor = textFieldBackgroundColorDark; |
| textFieldBorderColor= textFieldBorderColorDark; |
| } else { |
| textFieldBackgroundColor = textFieldBackgroundColorLight; |
| textFieldBorderColor = textFieldBorderColorLight; |
| } |
| |
| bool enabled = isEnabled(renderObject) && !isReadOnlyControl(renderObject); |
| int borderSize = textFieldBorderSize; |
| if (enabled && isFocused(renderObject)) |
| borderSize *= 2; |
| |
| if (!enabled) |
| graphicsContext.beginTransparencyLayer(disabledOpacity); |
| |
| 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 (enabled && isFocused(renderObject)) |
| graphicsContext.setFillColor(getAccentColor(renderObject)); |
| else |
| graphicsContext.setFillColor(textFieldBorderColor); |
| graphicsContext.fillPath(path); |
| path.clear(); |
| |
| path.addRoundedRect(fieldRect, corner); |
| graphicsContext.setFillRule(WindRule::NonZero); |
| 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 |
| |
| if (!enabled) |
| graphicsContext.endTransparencyLayer(); |
| |
| 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* element) const |
| { |
| RenderTheme::adjustMenuListStyle(style, element); |
| 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; |
| |
| if (renderObject.useDarkAppearance()) |
| progressBarBackgroundColor = progressBarBackgroundColorDark; |
| else |
| progressBarBackgroundColor = progressBarBackgroundColorLight; |
| |
| FloatRect fieldRect = rect; |
| FloatSize corner(3, 3); |
| Path path; |
| |
| 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(getAccentColor(renderObject)); |
| 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; |
| |
| if (renderObject.useDarkAppearance()) |
| sliderTrackBackgroundColor = sliderTrackBackgroundColorDark; |
| else |
| sliderTrackBackgroundColor = sliderTrackBackgroundColorLight; |
| |
| if (!isEnabled(renderObject)) |
| graphicsContext.beginTransparencyLayer(disabledOpacity); |
| |
| FloatSize corner(3, 3); |
| Path path; |
| |
| path.addRoundedRect(fieldRect, corner); |
| graphicsContext.setFillRule(WindRule::NonZero); |
| graphicsContext.setFillColor(sliderTrackBackgroundColor); |
| graphicsContext.fillPath(path); |
| path.clear(); |
| |
| LayoutPoint thumbLocation; |
| if (is<HTMLInputElement>(renderObject.node())) { |
| auto& input = downcast<HTMLInputElement>(*renderObject.node()); |
| if (auto* element = input.sliderThumbElement()) |
| thumbLocation = element->renderBox()->location() + LayoutPoint(sliderThumbSize / 2, 0); |
| } |
| 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(getAccentColor(renderObject)); |
| graphicsContext.fillPath(path); |
| |
| #if ENABLE(DATALIST_ELEMENT) |
| paintSliderTicks(renderObject, paintInfo, rect); |
| #endif |
| |
| if (isFocused(renderObject)) |
| ThemeAdwaita::paintFocus(graphicsContext, fieldRect, sliderTrackFocusOffset, renderObject.useDarkAppearance()); |
| |
| if (!isEnabled(renderObject)) |
| graphicsContext.endTransparencyLayer(); |
| |
| 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(getAccentColor(renderObject)); |
| 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(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 |
| |
| void RenderThemeAdwaita::setAccentColor(const Color& color) |
| { |
| static_cast<ThemeAdwaita&>(Theme::singleton()).setAccentColor(color); |
| platformColorsDidChange(); |
| } |
| |
| } // namespace WebCore |