blob: 1db9987ed4b91257f55d95afed0487c7b09471fb [file]
/*
* Copyright (C) 2026 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 "AdwaitaScrollbarPainter.h"
#if USE(THEME_ADWAITA)
#include "GraphicsContext.h"
namespace WebCore::AdwaitaScrollbarPainter {
void paint(GraphicsContext& graphicsContext, const IntRect& damageRect, const State& scrollbar)
{
if (graphicsContext.paintingDisabled())
return;
if (!scrollbar.enabled && scrollbar.usesOverlayScrollbars)
return;
IntRect rect = scrollbar.frameRect;
if (!rect.intersects(damageRect))
return;
double opacity;
if (scrollbar.usesOverlayScrollbars)
opacity = scrollbar.opacity;
else
opacity = 1;
if (!opacity)
return;
SRGBA<uint8_t> scrollbarBackgroundColor;
SRGBA<uint8_t> scrollbarBorderColor;
SRGBA<uint8_t> overlayThumbBorderColor;
SRGBA<uint8_t> overlayTroughBorderColor;
SRGBA<uint8_t> overlayTroughColor;
SRGBA<uint8_t> thumbHoveredColor;
SRGBA<uint8_t> thumbPressedColor;
SRGBA<uint8_t> thumbColor;
if (scrollbar.useDarkAppearanceForScrollbars) {
scrollbarBackgroundColor = scrollbarBackgroundColorDark;
scrollbarBorderColor = scrollbarBorderColorDark;
overlayThumbBorderColor = overlayThumbBorderColorDark;
overlayTroughBorderColor = overlayThumbBorderColorDark;
overlayTroughColor = overlayTroughColorDark;
thumbHoveredColor = thumbHoveredColorDark;
thumbPressedColor = thumbPressedColorDark;
thumbColor = thumbColorDark;
} else {
scrollbarBackgroundColor = scrollbarBackgroundColorLight;
scrollbarBorderColor = scrollbarBorderColorLight;
overlayThumbBorderColor = overlayThumbBorderColorLight;
overlayTroughBorderColor = overlayThumbBorderColorLight;
overlayTroughColor = overlayTroughColorLight;
thumbHoveredColor = thumbHoveredColorLight;
thumbPressedColor = thumbPressedColorLight;
thumbColor = thumbColorLight;
}
GraphicsContextStateSaver stateSaver(graphicsContext);
if (opacity != 1) {
graphicsContext.clip(damageRect);
graphicsContext.beginTransparencyLayer(opacity);
}
int thumbSize = scrollbarSize - scrollbarBorderSize - horizThumbMargin * 2;
if (!scrollbar.usesOverlayScrollbars) {
graphicsContext.fillRect(rect, scrollbarBackgroundColor);
IntRect frame = rect;
if (scrollbar.orientation == ScrollbarOrientation::Vertical) {
if (scrollbar.shouldPlaceVerticalScrollbarOnLeft)
frame.move(frame.width() - scrollbarBorderSize, 0);
frame.setWidth(scrollbarBorderSize);
} else
frame.setHeight(scrollbarBorderSize);
graphicsContext.fillRect(frame, scrollbarBorderColor);
} else if (scrollbar.hoveredPart != NoPart) {
int thumbCornerSize = thumbSize / 2;
FloatSize corner(thumbCornerSize, thumbCornerSize);
FloatSize borderCorner(thumbCornerSize + thumbBorderSize, thumbCornerSize + thumbBorderSize);
IntRect trough = rect;
if (scrollbar.orientation == ScrollbarOrientation::Vertical) {
if (scrollbar.shouldPlaceVerticalScrollbarOnLeft)
trough.move(scrollbarSize - (scrollbarSize / 2 + thumbSize / 2) - scrollbarBorderSize, vertThumbMargin);
else
trough.move(scrollbarSize - (scrollbarSize / 2 + thumbSize / 2), vertThumbMargin);
trough.setWidth(thumbSize);
trough.setHeight(rect.height() - vertThumbMargin * 2);
} else {
trough.move(vertThumbMargin, scrollbarSize - (scrollbarSize / 2 + thumbSize / 2));
trough.setWidth(rect.width() - vertThumbMargin * 2);
trough.setHeight(thumbSize);
}
IntRect troughBorder(trough);
troughBorder.inflate(thumbBorderSize);
Path path;
path.addRoundedRect(trough, corner);
graphicsContext.setFillRule(WindRule::NonZero);
graphicsContext.setFillColor(overlayTroughColor);
graphicsContext.fillPath(path);
path.clear();
path.addRoundedRect(trough, corner);
path.addRoundedRect(troughBorder, borderCorner);
graphicsContext.setFillRule(WindRule::EvenOdd);
graphicsContext.setFillColor(overlayTroughBorderColor);
graphicsContext.fillPath(path);
}
int thumbCornerSize;
int thumbPos = scrollbar.thumbPosition;
int thumbLen = scrollbar.thumbLength;
IntRect thumb = rect;
if (scrollbar.hoveredPart == NoPart && scrollbar.usesOverlayScrollbars) {
thumbCornerSize = overlayThumbSize / 2;
if (scrollbar.orientation == ScrollbarOrientation::Vertical) {
if (scrollbar.shouldPlaceVerticalScrollbarOnLeft)
thumb.move(horizOverlayThumbMargin, thumbPos + vertThumbMargin);
else
thumb.move(scrollbarSize - overlayThumbSize - horizOverlayThumbMargin, thumbPos + vertThumbMargin);
thumb.setWidth(overlayThumbSize);
thumb.setHeight(thumbLen - vertThumbMargin * 2);
} else {
thumb.move(thumbPos + vertThumbMargin, scrollbarSize - overlayThumbSize - horizOverlayThumbMargin);
thumb.setWidth(thumbLen - vertThumbMargin * 2);
thumb.setHeight(overlayThumbSize);
}
} else {
thumbCornerSize = thumbSize / 2;
if (scrollbar.orientation == ScrollbarOrientation::Vertical) {
if (scrollbar.shouldPlaceVerticalScrollbarOnLeft)
thumb.move(scrollbarSize - (scrollbarSize / 2 + thumbSize / 2) - scrollbarBorderSize, thumbPos + vertThumbMargin);
else
thumb.move(scrollbarSize - (scrollbarSize / 2 + thumbSize / 2), thumbPos + vertThumbMargin);
thumb.setWidth(thumbSize);
thumb.setHeight(thumbLen - vertThumbMargin * 2);
} else {
thumb.move(thumbPos + vertThumbMargin, scrollbarSize - (scrollbarSize / 2 + thumbSize / 2));
thumb.setWidth(thumbLen - vertThumbMargin * 2);
thumb.setHeight(thumbSize);
}
}
FloatSize corner(thumbCornerSize, thumbCornerSize);
FloatSize borderCorner(thumbCornerSize + thumbBorderSize, thumbCornerSize + thumbBorderSize);
Path path;
path.addRoundedRect(thumb, corner);
graphicsContext.setFillRule(WindRule::NonZero);
if (scrollbar.pressedPart == ThumbPart)
graphicsContext.setFillColor(thumbPressedColor);
else if (scrollbar.hoveredPart == ThumbPart)
graphicsContext.setFillColor(thumbHoveredColor);
else
graphicsContext.setFillColor(thumbColor);
graphicsContext.fillPath(path);
path.clear();
if (scrollbar.usesOverlayScrollbars) {
IntRect thumbBorder(thumb);
thumbBorder.inflate(thumbBorderSize);
path.addRoundedRect(thumb, corner);
path.addRoundedRect(thumbBorder, borderCorner);
graphicsContext.setFillRule(WindRule::EvenOdd);
graphicsContext.setFillColor(overlayThumbBorderColor);
graphicsContext.fillPath(path);
}
if (opacity != 1)
graphicsContext.endTransparencyLayer();
}
} // namespace WebCore::AdwaitaScrollbarPainter
#endif // USE(THEME_ADWAITA)