Modified: trunk/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp (199343 => 199344)
--- trunk/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp 2016-04-12 12:21:57 UTC (rev 199343)
+++ trunk/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp 2016-04-12 12:42:57 UTC (rev 199344)
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2016 Igalia S.L.
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,11 +30,11 @@
#include "GRefPtrGtk.h"
#include "PlatformContextCairo.h"
#include "PlatformMouseEvent.h"
+#include "RenderThemeGadget.h"
#include "ScrollView.h"
#include "Scrollbar.h"
#include <gtk/gtk.h>
#include <wtf/NeverDestroyed.h>
-#include <wtf/TemporaryChange.h>
namespace WebCore {
@@ -47,332 +48,546 @@
{
}
-bool ScrollbarThemeGtk::hasThumb(Scrollbar& scrollbar)
+#ifndef GTK_API_VERSION_2
+static void themeChangedCallback()
{
-#ifndef GTK_API_VERSION_2
- // This method is just called as a paint-time optimization to see if
- // painting the thumb can be skipped. We don't have to be exact here.
- return thumbLength(scrollbar) > 0;
+ ScrollbarTheme::theme().themeChanged();
+}
+
+ScrollbarThemeGtk::ScrollbarThemeGtk()
+{
+#if GTK_CHECK_VERSION(3, 20, 0)
+#if USE(COORDINATED_GRAPHICS_THREADED)
+ m_usesOverlayScrollbars = true;
#else
- UNUSED_PARAM(scrollbar);
- return false;
+ m_usesOverlayScrollbars = g_strcmp0(g_getenv("GTK_OVERLAY_SCROLLING"), "0");
#endif
+#endif
+ static bool themeMonitorInitialized = false;
+ if (!themeMonitorInitialized) {
+ g_signal_connect(gtk_settings_get_default(), "notify::gtk-theme-name", G_CALLBACK(themeChangedCallback), nullptr);
+ themeMonitorInitialized = true;
+ updateThemeProperties();
+ }
}
-IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool painting)
+#if !GTK_CHECK_VERSION(3, 20, 0)
+static GRefPtr<GtkStyleContext> createStyleContext(Scrollbar* scrollbar = nullptr)
{
-#ifndef GTK_API_VERSION_2
- if (part == BackButtonEndPart && !m_hasBackButtonEndPart)
- return IntRect();
- if (part == BackButtonStartPart && !m_hasBackButtonStartPart)
- return IntRect();
+ GRefPtr<GtkStyleContext> styleContext = adoptGRef(gtk_style_context_new());
+ GRefPtr<GtkWidgetPath> path = adoptGRef(gtk_widget_path_new());
+ gtk_widget_path_append_type(path.get(), GTK_TYPE_SCROLLBAR);
+ gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SCROLLBAR);
+ gtk_widget_path_iter_add_class(path.get(), -1, scrollbar && scrollbar->orientation() == HorizontalScrollbar ? "horizontal" : "vertical");
+ gtk_style_context_set_path(styleContext.get(), path.get());
+ return styleContext;
+}
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar, painting ? StyleContextMode::Paint : StyleContextMode::Layout);
- GtkBorder troughBorder;
- getTroughBorder(scrollbar, &troughBorder);
- int x = scrollbar.x() + troughBorder.left;
- int y = scrollbar.y() + troughBorder.top;
- IntSize size = buttonSize(scrollbar, part);
- if (part == BackButtonStartPart)
- return IntRect(x, y, size.width(), size.height());
+static GRefPtr<GtkStyleContext> createChildStyleContext(GtkStyleContext* parent, const char* className)
+{
+ ASSERT(parent);
+ GRefPtr<GtkWidgetPath> path = adoptGRef(gtk_widget_path_copy(gtk_style_context_get_path(parent)));
+ gtk_widget_path_append_type(path.get(), GTK_TYPE_SCROLLBAR);
+ gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SCROLLBAR);
+ gtk_widget_path_iter_add_class(path.get(), -1, className);
- // BackButtonEndPart (alternate button)
- if (scrollbar.orientation() == HorizontalScrollbar)
- return IntRect(scrollbar.x() + scrollbar.width() - troughBorder.left - (2 * size.width()), y, size.width(), size.height());
+ GRefPtr<GtkStyleContext> styleContext = adoptGRef(gtk_style_context_new());
+ gtk_style_context_set_path(styleContext.get(), path.get());
+ gtk_style_context_set_parent(styleContext.get(), parent);
+ return styleContext;
+}
+#endif // GTK_CHECK_VERSION(3, 20, 0)
- // VerticalScrollbar alternate button
- return IntRect(x, scrollbar.y() + scrollbar.height() - troughBorder.top - (2 * size.height()), size.width(), size.height());
+void ScrollbarThemeGtk::themeChanged()
+{
+ updateThemeProperties();
+}
+
+#if GTK_CHECK_VERSION(3, 20, 0)
+void ScrollbarThemeGtk::updateThemeProperties()
+{
+ auto steppers = static_cast<RenderThemeScrollbarGadget*>(RenderThemeGadget::create({ RenderThemeGadget::Type::Scrollbar, "scrollbar", GTK_STATE_FLAG_NORMAL, { } }).get())->steppers();
+ m_hasBackButtonStartPart = steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward);
+ m_hasForwardButtonEndPart = steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward);
+ m_hasBackButtonEndPart = steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward);
+ m_hasForwardButtonStartPart = steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward);
+}
#else
- UNUSED_PARAM(scrollbar);
- UNUSED_PARAM(part);
- UNUSED_PARAM(painting);
- return IntRect();
-#endif
+void ScrollbarThemeGtk::updateThemeProperties()
+{
+ gboolean hasBackButtonStartPart, hasForwardButtonEndPart, hasBackButtonEndPart, hasForwardButtonStartPart;
+ gtk_style_context_get_style(createStyleContext().get(),
+ "has-backward-stepper", &hasBackButtonStartPart,
+ "has-forward-stepper", &hasForwardButtonEndPart,
+ "has-secondary-backward-stepper", &hasBackButtonEndPart,
+ "has-secondary-forward-stepper", &hasForwardButtonStartPart,
+ nullptr);
+ m_hasBackButtonStartPart = hasBackButtonStartPart;
+ m_hasForwardButtonEndPart = hasForwardButtonEndPart;
+ m_hasBackButtonEndPart = hasBackButtonEndPart;
+ m_hasForwardButtonStartPart = hasForwardButtonStartPart;
}
+#endif // GTK_CHECK_VERSION(3, 20, 0)
-IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool painting)
+#if GTK_CHECK_VERSION(3, 20, 0)
+static GtkStateFlags scrollbarPartStateFlags(Scrollbar& scrollbar, ScrollbarPart part, bool painting = false)
{
-#ifndef GTK_API_VERSION_2
- if (part == ForwardButtonStartPart && !m_hasForwardButtonStartPart)
- return IntRect();
- if (part == ForwardButtonEndPart && !m_hasForwardButtonEndPart)
- return IntRect();
+ unsigned stateFlags = 0;
+ switch (part) {
+ case AllParts:
+ if (!painting || scrollbar.hoveredPart() != NoPart)
+ stateFlags |= GTK_STATE_FLAG_PRELIGHT;
+ break;
+ case BackTrackPart:
+ case ForwardTrackPart:
+ if (scrollbar.hoveredPart() == BackTrackPart || scrollbar.hoveredPart() == ForwardTrackPart)
+ stateFlags |= GTK_STATE_FLAG_PRELIGHT;
+ if (scrollbar.pressedPart() == BackTrackPart || scrollbar.pressedPart() == ForwardTrackPart)
+ stateFlags |= GTK_STATE_FLAG_ACTIVE;
+ break;
+ case BackButtonStartPart:
+ case ForwardButtonStartPart:
+ case BackButtonEndPart:
+ case ForwardButtonEndPart:
+ if (((part == BackButtonStartPart || part == BackButtonEndPart) && !scrollbar.currentPos())
+ || ((part == ForwardButtonEndPart || part == ForwardButtonStartPart) && scrollbar.currentPos() == scrollbar.maximum())) {
+ stateFlags |= GTK_STATE_FLAG_INSENSITIVE;
+ break;
+ }
+ FALLTHROUGH;
+ default:
+ if (scrollbar.hoveredPart() == part)
+ stateFlags |= GTK_STATE_FLAG_PRELIGHT;
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar, painting ? StyleContextMode::Paint : StyleContextMode::Layout);
- GtkBorder troughBorder;
- getTroughBorder(scrollbar, &troughBorder);
- IntSize size = buttonSize(scrollbar, part);
- if (scrollbar.orientation() == HorizontalScrollbar) {
- int y = scrollbar.y() + troughBorder.top;
- if (part == ForwardButtonEndPart)
- return IntRect(scrollbar.x() + scrollbar.width() - size.width() - troughBorder.left, y, size.width(), size.height());
+ if (scrollbar.pressedPart() == part)
+ stateFlags |= GTK_STATE_FLAG_ACTIVE;
+ break;
+ }
- // ForwardButtonStartPart (alternate button)
- return IntRect(scrollbar.x() + troughBorder.left + size.width(), y, size.width(), size.height());
+ return static_cast<GtkStateFlags>(stateFlags);
+}
+
+static std::unique_ptr<RenderThemeGadget> scrollbarGadgetForLayout(Scrollbar& scrollbar)
+{
+ RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", scrollbarPartStateFlags(scrollbar, AllParts), { } };
+ if (scrollbar.orientation() == VerticalScrollbar) {
+ info.classList.append("vertical");
+ info.classList.append("right");
+ } else {
+ info.classList.append("horizontal");
+ info.classList.append("bottom");
}
+ if (scrollbar.isOverlayScrollbar())
+ info.classList.append("overlay-indicator");
+ if (info.state & GTK_STATE_FLAG_PRELIGHT)
+ info.classList.append("hovering");
- // VerticalScrollbar
- int x = scrollbar.x() + troughBorder.left;
- if (part == ForwardButtonEndPart)
- return IntRect(x, scrollbar.y() + scrollbar.height() - size.height() - troughBorder.top, size.width(), size.height());
+ return RenderThemeGadget::create(info);
+}
- // ForwardButtonStartPart (alternate button)
- return IntRect(x, scrollbar.y() + troughBorder.top + size.height(), size.width(), size.height());
-#else
- UNUSED_PARAM(scrollbar);
- UNUSED_PARAM(part);
- UNUSED_PARAM(painting);
- return IntRect();
-#endif
+static std::unique_ptr<RenderThemeBoxGadget> contentsGadgetForLayout(Scrollbar& scrollbar, RenderThemeGadget* parent, IntRect& contentsRect, Vector<int, 4> steppersPosition)
+{
+ Vector<RenderThemeGadget::Info> children;
+ auto steppers = static_cast<RenderThemeScrollbarGadget*>(parent)->steppers();
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward)) {
+ steppersPosition[0] = 0;
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, BackButtonStartPart), { "up" } });
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) {
+ steppersPosition[1] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, ForwardButtonStartPart), { "down" } });
+ }
+ children.append({ RenderThemeGadget::Type::Generic, "trough", scrollbarPartStateFlags(scrollbar, BackTrackPart), { } });
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) {
+ steppersPosition[2] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, BackButtonEndPart), { "up" } });
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward)) {
+ steppersPosition[3] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, ForwardButtonEndPart), { "down" } });
+ }
+ RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "contents", GTK_STATE_FLAG_NORMAL, { } };
+ auto contentsGadget = std::make_unique<RenderThemeBoxGadget>(info, children, parent);
+
+ GtkBorder scrollbarContentsBox = parent->contentsBox();
+ GtkBorder contentsContentsBox = contentsGadget->contentsBox();
+ GtkBorder padding;
+ padding.left = scrollbarContentsBox.left + contentsContentsBox.left;
+ padding.right = scrollbarContentsBox.right + contentsContentsBox.right;
+ padding.top = scrollbarContentsBox.top + contentsContentsBox.top;
+ padding.bottom = scrollbarContentsBox.bottom + contentsContentsBox.bottom;
+ contentsRect = scrollbar.frameRect();
+ contentsRect.move(padding.left, padding.top);
+ contentsRect.contract(padding.left + padding.right, padding.top + padding.bottom);
+ return contentsGadget;
}
-IntRect ScrollbarThemeGtk::trackRect(Scrollbar& scrollbar, bool painting)
+IntRect ScrollbarThemeGtk::trackRect(Scrollbar& scrollbar, bool /*painting*/)
{
-#ifndef GTK_API_VERSION_2
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar, painting ? StyleContextMode::Paint : StyleContextMode::Layout);
+ auto scrollbarGadget = scrollbarGadgetForLayout(scrollbar);
+ IntRect rect;
+ Vector<int, 4> steppersPosition(4, -1);
+ auto contentsGadget = contentsGadgetForLayout(scrollbar, scrollbarGadget.get(), rect, steppersPosition);
+
+ if (steppersPosition[0] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.move(0, contentsGadget->child(steppersPosition[0])->preferredSize().height());
+ else
+ rect.move(contentsGadget->child(steppersPosition[0])->preferredSize().width(), 0);
+ }
+ if (steppersPosition[1] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.move(0, contentsGadget->child(steppersPosition[1])->preferredSize().height());
+ else
+ rect.move(contentsGadget->child(steppersPosition[1])->preferredSize().width(), 0);
+ }
+ if (steppersPosition[2] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.contract(0, contentsGadget->child(steppersPosition[2])->preferredSize().height());
+ else
+ rect.contract(contentsGadget->child(steppersPosition[2])->preferredSize().width(), 0);
+ }
+ if (steppersPosition[3] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.contract(0, contentsGadget->child(steppersPosition[3])->preferredSize().height());
+ else
+ rect.contract(contentsGadget->child(steppersPosition[3])->preferredSize().width(), 0);
+ }
+
+ if (scrollbar.orientation() == VerticalScrollbar)
+ return scrollbar.height() < rect.height() ? IntRect() : rect;
+
+ return scrollbar.width() < rect.width() ? IntRect() : rect;
+}
+#else
+IntRect ScrollbarThemeGtk::trackRect(Scrollbar& scrollbar, bool /*painting*/)
+{
+ GRefPtr<GtkStyleContext> styleContext = createStyleContext(&scrollbar);
// The padding along the thumb movement axis includes the trough border
// plus the size of stepper spacing (the space between the stepper and
// the place where the thumb stops). There is often no stepper spacing.
- GtkBorder troughBorder;
- getTroughBorder(scrollbar, &troughBorder);
- GtkBorder stepperSpacing = { 0, 0, 0, 0 };
+ int stepperSpacing, stepperSize, troughBorderWidth, thumbFat;
+ gtk_style_context_get_style(styleContext.get(), "stepper-spacing", &stepperSpacing, "stepper-size", &stepperSize, "trough-border",
+ &troughBorderWidth, "slider-width", &thumbFat, nullptr);
// The fatness of the scrollbar on the non-movement axis.
- int thickness = scrollbarThickness(styleContext.get(), scrollbar.orientation());
+ int thickness = thumbFat + 2 * troughBorderWidth;
int startButtonsOffset = 0;
int buttonsWidth = 0;
if (m_hasForwardButtonStartPart) {
- int buttonSize = stepperSize(scrollbar, ForwardButtonStartPart);
- startButtonsOffset += buttonSize;
- buttonsWidth += buttonSize;
+ startButtonsOffset += stepperSize;
+ buttonsWidth += stepperSize;
}
if (m_hasBackButtonStartPart) {
- int buttonSize = stepperSize(scrollbar, BackButtonStartPart);
- startButtonsOffset += buttonSize;
- buttonsWidth += buttonSize;
- GtkBorder margin;
- getStepperSpacing(scrollbar, BackButtonStartPart, &margin);
- stepperSpacing.left += margin.left;
- stepperSpacing.right += margin.right;
- stepperSpacing.top += margin.top;
- stepperSpacing.bottom += margin.bottom;
+ startButtonsOffset += stepperSize;
+ buttonsWidth += stepperSize;
}
if (m_hasBackButtonEndPart)
- buttonsWidth += stepperSize(scrollbar, BackButtonEndPart);
- if (m_hasForwardButtonEndPart) {
- buttonsWidth += stepperSize(scrollbar, ForwardButtonEndPart);
- GtkBorder margin;
- getStepperSpacing(scrollbar, BackButtonStartPart, &margin);
- stepperSpacing.left += margin.left;
- stepperSpacing.right += margin.right;
- stepperSpacing.top += margin.top;
- stepperSpacing.bottom += margin.bottom;
- }
+ buttonsWidth += stepperSize;
+ if (m_hasForwardButtonEndPart)
+ buttonsWidth += stepperSize;
if (scrollbar.orientation() == HorizontalScrollbar) {
// Once the scrollbar becomes smaller than the natural size of the two buttons and the thumb, the track disappears.
if (scrollbar.width() < buttonsWidth + minimumThumbLength(scrollbar))
return IntRect();
- return IntRect(scrollbar.x() + troughBorder.left + stepperSpacing.left + startButtonsOffset, scrollbar.y(),
- scrollbar.width() - (troughBorder.left + troughBorder.right) - (stepperSpacing.left + stepperSpacing.right) - buttonsWidth, thickness);
+ return IntRect(scrollbar.x() + troughBorderWidth + stepperSpacing + startButtonsOffset, scrollbar.y(),
+ scrollbar.width() - (2 * troughBorderWidth) - (2 * stepperSpacing) - buttonsWidth, thickness);
}
if (scrollbar.height() < buttonsWidth + minimumThumbLength(scrollbar))
return IntRect();
- return IntRect(scrollbar.x(), scrollbar.y() + troughBorder.top + stepperSpacing.top + startButtonsOffset,
- thickness, scrollbar.height() - (troughBorder.top + troughBorder.bottom) - (stepperSpacing.top + stepperSpacing.bottom) - buttonsWidth);
-#else
- UNUSED_PARAM(scrollbar);
- UNUSED_PARAM(painting);
- return IntRect();
+ return IntRect(scrollbar.x(), scrollbar.y() + troughBorderWidth + stepperSpacing + startButtonsOffset,
+ thickness, scrollbar.height() - (2 * troughBorderWidth) - (2 * stepperSpacing) - buttonsWidth);
+}
#endif
+
+bool ScrollbarThemeGtk::hasThumb(Scrollbar& scrollbar)
+{
+ // This method is just called as a paint-time optimization to see if
+ // painting the thumb can be skipped. We don't have to be exact here.
+ return thumbLength(scrollbar) > 0;
}
-#ifndef GTK_API_VERSION_2
-// The GtkStyleContext returned by this function is cached by ScrollbarThemeGtk::paint for the
-// duration of its scope, so a different GtkStyleContext with updated theme properties will be
-// used for each call to paint.
-GRefPtr<GtkStyleContext> ScrollbarThemeGtk::getOrCreateStyleContext(Scrollbar* scrollbar, StyleContextMode mode)
+#if GTK_CHECK_VERSION(3, 20, 0)
+IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool /*painting*/)
{
- ASSERT(scrollbar || mode == StyleContextMode::Layout);
- if (m_cachedStyleContext)
- return m_cachedStyleContext;
+ ASSERT(part == BackButtonStartPart || part == BackButtonEndPart);
+ if ((part == BackButtonEndPart && !m_hasBackButtonEndPart) || (part == BackButtonStartPart && !m_hasBackButtonStartPart))
+ return IntRect();
- GRefPtr<GtkStyleContext> styleContext = adoptGRef(gtk_style_context_new());
- GRefPtr<GtkWidgetPath> path = adoptGRef(gtk_widget_path_new());
- gtk_widget_path_append_type(path.get(), GTK_TYPE_SCROLLBAR);
-#if GTK_CHECK_VERSION(3, 19, 2)
- gtk_widget_path_iter_set_object_name(path.get(), -1, "scrollbar");
- if (m_usesOverlayScrollbars) {
- gtk_widget_path_iter_add_class(path.get(), -1, "overlay-indicator");
- if (mode == StyleContextMode::Layout || scrollbar->hoveredPart() != NoPart)
- gtk_widget_path_iter_add_class(path.get(), -1, "hovering");
+ auto scrollbarGadget = scrollbarGadgetForLayout(scrollbar);
+ IntRect rect;
+ Vector<int, 4> steppersPosition(4, -1);
+ auto contentsGadget = contentsGadgetForLayout(scrollbar, scrollbarGadget.get(), rect, steppersPosition);
+
+ if (part == BackButtonStartPart)
+ return IntRect(rect.location(), contentsGadget->child(0)->preferredSize());
+
+ // Secondary back.
+ if (steppersPosition[1] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.move(0, contentsGadget->child(steppersPosition[1])->preferredSize().height());
+ else
+ rect.move(contentsGadget->child(steppersPosition[1])->preferredSize().width(), 0);
}
-#else
- gtk_widget_path_iter_add_class(path.get(), -1, "scrollbar");
-#endif
- ScrollbarOrientation orientation = scrollbar ? scrollbar->orientation() : VerticalScrollbar;
- gtk_widget_path_iter_add_class(path.get(), -1, orientation == VerticalScrollbar ? "vertical" : "horizontal");
- gtk_widget_path_iter_add_class(path.get(), -1, orientation == VerticalScrollbar ? "right" : "bottom");
- gtk_style_context_set_path(styleContext.get(), path.get());
- return styleContext;
-}
+ IntSize preferredSize = contentsGadget->child(steppersPosition[2])->preferredSize();
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.contract(0, preferredSize.height());
+ else
+ rect.contract(preferredSize.width(), 0);
-static GRefPtr<GtkStyleContext> createChildStyleContext(GtkStyleContext* parent, const char* name)
-{
- ASSERT(parent);
- GRefPtr<GtkWidgetPath> path = adoptGRef(gtk_widget_path_copy(gtk_style_context_get_path(parent)));
- gtk_widget_path_append_type(path.get(), GTK_TYPE_SCROLLBAR);
-#if GTK_CHECK_VERSION(3, 19, 2)
- gtk_widget_path_iter_set_object_name(path.get(), -1, name);
-#else
- gtk_widget_path_iter_add_class(path.get(), -1, GTK_STYLE_CLASS_SCROLLBAR);
- gtk_widget_path_iter_add_class(path.get(), -1, name);
-#endif
+ if (steppersPosition[3] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.contract(0, contentsGadget->child(steppersPosition[3])->preferredSize().height());
+ else
+ rect.contract(contentsGadget->child(steppersPosition[3])->preferredSize().width(), 0);
+ }
- GRefPtr<GtkStyleContext> styleContext = adoptGRef(gtk_style_context_new());
- gtk_style_context_set_path(styleContext.get(), path.get());
- gtk_style_context_set_parent(styleContext.get(), parent);
- return styleContext;
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.move(0, rect.height());
+ else
+ rect.move(rect.width(), 0);
+
+ return IntRect(rect.location(), preferredSize);
}
-static void themeChangedCallback()
+IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool /*painting*/)
{
- ScrollbarTheme::theme().themeChanged();
-}
+ ASSERT(part == ForwardButtonStartPart || part == ForwardButtonEndPart);
+ if ((part == ForwardButtonStartPart && !m_hasForwardButtonStartPart) || (part == ForwardButtonEndPart && !m_hasForwardButtonEndPart))
+ return IntRect();
-ScrollbarThemeGtk::ScrollbarThemeGtk()
-{
-#if GTK_CHECK_VERSION(3, 19, 2)
-#if USE(COORDINATED_GRAPHICS_THREADED)
- m_usesOverlayScrollbars = true;
-#else
- m_usesOverlayScrollbars = g_strcmp0(g_getenv("GTK_OVERLAY_SCROLLING"), "0");
-#endif
-#endif
- static bool themeMonitorInitialized = false;
- if (!themeMonitorInitialized) {
- g_signal_connect_swapped(gtk_settings_get_default(), "notify::gtk-theme-name", G_CALLBACK(themeChangedCallback), nullptr);
- themeMonitorInitialized = true;
+ auto scrollbarGadget = scrollbarGadgetForLayout(scrollbar);
+ IntRect rect;
+ Vector<int, 4> steppersPosition(4, -1);
+ auto contentsGadget = contentsGadgetForLayout(scrollbar, scrollbarGadget.get(), rect, steppersPosition);
+
+ if (steppersPosition[0] != -1) {
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.move(0, contentsGadget->child(steppersPosition[0])->preferredSize().height());
+ else
+ rect.move(contentsGadget->child(steppersPosition[0])->preferredSize().width(), 0);
}
- updateThemeProperties();
-}
+ if (part == ForwardButtonStartPart)
+ return IntRect(rect.location(), contentsGadget->child(1)->preferredSize());
-void ScrollbarThemeGtk::themeChanged()
-{
- updateThemeProperties();
-}
+ // Forward button.
+ IntSize preferredSize = contentsGadget->child(steppersPosition[3])->preferredSize();
+ if (scrollbar.orientation() == VerticalScrollbar)
+ rect.move(0, rect.height() - preferredSize.height());
+ else
+ rect.move(rect.width() - preferredSize.width(), 0);
-void ScrollbarThemeGtk::updateThemeProperties()
-{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext();
- gtk_style_context_get_style(
- styleContext.get(),
- "has-backward-stepper", &m_hasBackButtonStartPart,
- "has-forward-stepper", &m_hasForwardButtonEndPart,
- "has-secondary-backward-stepper", &m_hasBackButtonEndPart,
- "has-secondary-forward-stepper", &m_hasForwardButtonStartPart,
- nullptr);
+ return IntRect(rect.location(), preferredSize);
}
-
-IntRect ScrollbarThemeGtk::thumbRect(Scrollbar& scrollbar, const IntRect& unconstrainedTrackRect)
+#else
+IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool /*painting*/)
{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
- IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrainedTrackRect);
- int thumbPos = thumbPosition(scrollbar);
- int thumbFat = thumbFatness(scrollbar);
- GtkBorder troughBorder = { 0, 0, 0, 0 };
-#if GTK_CHECK_VERSION(3, 19, 11)
- getTroughBorder(scrollbar, &troughBorder);
-#endif
+ if ((part == BackButtonEndPart && !m_hasBackButtonEndPart) || (part == BackButtonStartPart && !m_hasBackButtonStartPart))
+ return IntRect();
+ GRefPtr<GtkStyleContext> styleContext = createStyleContext(&scrollbar);
+ int troughBorderWidth, stepperSize, thumbFat;
+ gtk_style_context_get_style(styleContext.get(), "trough-border", &troughBorderWidth, "stepper-size", &stepperSize, "slider-width", &thumbFat, nullptr);
+ int x = scrollbar.x() + troughBorderWidth;
+ int y = scrollbar.y() + troughBorderWidth;
+ if (part == BackButtonStartPart) {
+ if (scrollbar.orientation() == HorizontalScrollbar)
+ return IntRect(x, y, stepperSize, thumbFat);
+ return IntRect(x, y, thumbFat, stepperSize);
+ }
+
+ // BackButtonEndPart (alternate button)
if (scrollbar.orientation() == HorizontalScrollbar)
- return IntRect(trackRect.x() + thumbPos, trackRect.y() + troughBorder.top + (trackRect.height() - thumbFat) / 2, thumbLength(scrollbar), thumbFat);
+ return IntRect(scrollbar.x() + scrollbar.width() - troughBorderWidth - (2 * stepperSize), y, stepperSize, thumbFat);
- // VerticalScrollbar
- return IntRect(trackRect.x() + troughBorder.left + (trackRect.width() - thumbFat) / 2, trackRect.y() + thumbPos, thumbFat, thumbLength(scrollbar));
+ // VerticalScrollbar alternate button
+ return IntRect(x, scrollbar.y() + scrollbar.height() - troughBorderWidth - (2 * stepperSize), thumbFat, stepperSize);
}
-static void adjustRectAccordingToMargin(GtkStyleContext* context, IntRect& rect)
+IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool /*painting*/)
{
- GtkBorder margin;
- gtk_style_context_get_margin(context, gtk_style_context_get_state(context), &margin);
- rect.move(margin.left, margin.top);
- rect.contract(margin.left + margin.right, margin.top + margin.bottom);
-}
+ if ((part == ForwardButtonStartPart && !m_hasForwardButtonStartPart) || (part == ForwardButtonEndPart && !m_hasForwardButtonEndPart))
+ return IntRect();
-void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext& context, Scrollbar& scrollbar, const IntRect& rect)
-{
- GRefPtr<GtkStyleContext> parentStyleContext = getOrCreateStyleContext(&scrollbar, StyleContextMode::Paint);
- // Paint the track background. If the trough-under-steppers property is true, this
- // should be the full size of the scrollbar, but if is false, it should only be the
- // track rect.
- IntRect fullScrollbarRect(rect);
- if (troughUnderSteppers(scrollbar))
- fullScrollbarRect = IntRect(scrollbar.x(), scrollbar.y(), scrollbar.width(), scrollbar.height());
+ GRefPtr<GtkStyleContext> styleContext = createStyleContext(&scrollbar);
+ int troughBorderWidth, stepperSize, thumbFat;
+ gtk_style_context_get_style(styleContext.get(), "trough-border", &troughBorderWidth, "stepper-size", &stepperSize, "slider-width", &thumbFat, nullptr);
+ if (scrollbar.orientation() == HorizontalScrollbar) {
+ int y = scrollbar.y() + troughBorderWidth;
+ if (part == ForwardButtonEndPart)
+ return IntRect(scrollbar.x() + scrollbar.width() - stepperSize - troughBorderWidth, y, stepperSize, thumbFat);
- IntRect adjustedRect = fullScrollbarRect;
- adjustRectAccordingToMargin(parentStyleContext.get(), adjustedRect);
- gtk_render_background(parentStyleContext.get(), context.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
- gtk_render_frame(parentStyleContext.get(), context.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
+ // ForwardButtonStartPart (alternate button)
+ return IntRect(scrollbar.x() + troughBorderWidth + stepperSize, y, stepperSize, thumbFat);
+ }
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(parentStyleContext.get(), "contents");
- adjustedRect = fullScrollbarRect;
- adjustRectAccordingToMargin(contentsStyleContext.get(), adjustedRect);
- gtk_render_background(contentsStyleContext.get(), context.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
- gtk_render_frame(contentsStyleContext.get(), context.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
+ // VerticalScrollbar
+ int x = scrollbar.x() + troughBorderWidth;
+ if (part == ForwardButtonEndPart)
+ return IntRect(x, scrollbar.y() + scrollbar.height() - stepperSize - troughBorderWidth, thumbFat, stepperSize);
- GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(contentsStyleContext.get(), "trough");
- adjustedRect = fullScrollbarRect;
- adjustRectAccordingToMargin(troughStyleContext.get(), adjustedRect);
- gtk_render_background(troughStyleContext.get(), context.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
- gtk_render_frame(troughStyleContext.get(), context.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
+ // ForwardButtonStartPart (alternate button)
+ return IntRect(x, scrollbar.y() + troughBorderWidth + stepperSize, thumbFat, stepperSize);
}
+#endif // GTK_CHECK_VERSION(3, 20, 0)
-void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext& context, Scrollbar& scrollbar)
+#if GTK_CHECK_VERSION(3, 20, 0)
+bool ScrollbarThemeGtk::paint(Scrollbar& scrollbar, GraphicsContext& graphicsContext, const IntRect& damageRect)
{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar, StyleContextMode::Paint);
- gtk_render_frame(styleContext.get(), context.platformContext()->cr(), scrollbar.x(), scrollbar.y(), scrollbar.width(), scrollbar.height());
-}
+ if (graphicsContext.paintingDisabled())
+ return false;
-void ScrollbarThemeGtk::paintThumb(GraphicsContext& context, Scrollbar& scrollbar, const IntRect& rect)
-{
- ScrollbarOrientation orientation = scrollbar.orientation();
- GRefPtr<GtkStyleContext> parentStyleContext = getOrCreateStyleContext(&scrollbar, StyleContextMode::Paint);
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(parentStyleContext.get(), "contents");
- GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(contentsStyleContext.get(), "trough");
- GRefPtr<GtkStyleContext> styleContext = createChildStyleContext(troughStyleContext.get(), "slider");
+ double opacity = scrollbar.hoveredPart() == NoPart ? scrollbar.opacity() : 1;
+ if (!opacity)
+ return true;
- unsigned flags = 0;
- if (scrollbar.pressedPart() == ThumbPart)
- flags |= GTK_STATE_FLAG_ACTIVE;
- if (scrollbar.hoveredPart() == ThumbPart)
- flags |= GTK_STATE_FLAG_PRELIGHT;
- gtk_style_context_set_state(styleContext.get(), static_cast<GtkStateFlags>(flags));
+ IntRect rect = scrollbar.frameRect();
+ if (!rect.intersects(damageRect))
+ return true;
- IntRect thumbRect(rect);
- if (m_usesOverlayScrollbars && scrollbar.hoveredPart() == NoPart) {
+ RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", scrollbarPartStateFlags(scrollbar, AllParts, true), { } };
+ if (scrollbar.orientation() == VerticalScrollbar) {
+ info.classList.append("vertical");
+ info.classList.append("right");
+ } else {
+ info.classList.append("horizontal");
+ info.classList.append("bottom");
+ }
+ if (m_usesOverlayScrollbars)
+ info.classList.append("overlay-indicator");
+ if (info.state & GTK_STATE_FLAG_PRELIGHT)
+ info.classList.append("hovering");
+ if (scrollbar.pressedPart() != NoPart)
+ info.classList.append("dragging");
+ auto scrollbarGadget = RenderThemeGadget::create(info);
+ if (m_usesOverlayScrollbars)
+ opacity *= scrollbarGadget->opacity();
+ if (!opacity)
+ return true;
+
+ info.type = RenderThemeGadget::Type::Generic;
+ info.name = "contents";
+ info.state = GTK_STATE_FLAG_NORMAL;
+ info.classList.clear();
+ Vector<RenderThemeGadget::Info> children;
+ auto steppers = static_cast<RenderThemeScrollbarGadget*>(scrollbarGadget.get())->steppers();
+ unsigned steppersPosition[4] = { 0, 0, 0, 0 };
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward)) {
+ steppersPosition[0] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, BackButtonStartPart), { "up" } });
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) {
+ steppersPosition[1] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, ForwardButtonStartPart), { "down" } });
+ }
+ unsigned troughPosition = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "trough", scrollbarPartStateFlags(scrollbar, BackTrackPart), { } });
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) {
+ steppersPosition[2] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, BackButtonEndPart), { "up" } });
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward)) {
+ steppersPosition[3] = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "button", scrollbarPartStateFlags(scrollbar, ForwardButtonEndPart), { "down" } });
+ }
+ auto contentsGadget = std::make_unique<RenderThemeBoxGadget>(info, children, scrollbarGadget.get());
+ RenderThemeGadget* troughGadget = contentsGadget->child(troughPosition);
+
+ if (opacity != 1) {
+ graphicsContext.save();
+ graphicsContext.clip(damageRect);
+ graphicsContext.beginTransparencyLayer(opacity);
+ }
+
+ FloatRect contentsRect;
+ scrollbarGadget->render(graphicsContext.platformContext()->cr(), rect, &contentsRect);
+ contentsGadget->render(graphicsContext.platformContext()->cr(), contentsRect, &contentsRect);
+ troughGadget->render(graphicsContext.platformContext()->cr(), contentsRect, &contentsRect);
+ FloatRect buttonRect = contentsRect;
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward)) {
+ RenderThemeGadget* buttonGadget = contentsGadget->child(steppersPosition[0]);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.setHeight(buttonGadget->preferredSize().height());
+ else
+ buttonRect.setWidth(buttonGadget->preferredSize().width());
+ buttonGadget->render(graphicsContext.platformContext()->cr(), buttonRect);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.move(0, buttonRect.height());
+ else
+ buttonRect.move(buttonRect.width(), 0);
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) {
+ RenderThemeGadget* buttonGadget = contentsGadget->child(steppersPosition[1]);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.setHeight(buttonGadget->preferredSize().height());
+ else
+ buttonRect.setWidth(buttonGadget->preferredSize().width());
+ buttonGadget->render(graphicsContext.platformContext()->cr(), buttonRect);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.move(0, contentsRect.height());
+ else
+ buttonRect.move(contentsRect.width(), 0);
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) {
+ RenderThemeGadget* buttonGadget = contentsGadget->child(steppersPosition[2]);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.setHeight(buttonGadget->preferredSize().height());
+ else
+ buttonRect.setWidth(buttonGadget->preferredSize().width());
+ buttonGadget->render(graphicsContext.platformContext()->cr(), buttonRect);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.move(0, buttonRect.height());
+ else
+ buttonRect.move(buttonRect.width(), 0);
+ }
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward)) {
+ RenderThemeGadget* buttonGadget = contentsGadget->child(steppersPosition[3]);
+ if (scrollbar.orientation() == VerticalScrollbar)
+ buttonRect.setHeight(buttonGadget->preferredSize().height());
+ else
+ buttonRect.setWidth(buttonGadget->preferredSize().width());
+ buttonGadget->render(graphicsContext.platformContext()->cr(), buttonRect);
+ }
+ if (int thumbSize = thumbLength(scrollbar)) {
+ info.name = "slider";
+ info.state = scrollbarPartStateFlags(scrollbar, ThumbPart);
+ auto sliderGadget = RenderThemeGadget::create(info, troughGadget);
+
// When using overlay scrollbars we always claim the size of the scrollbar when hovered, so when
// drawing the indicator we need to adjust the rectangle to its actual size in indicator mode.
- if (orientation == VerticalScrollbar)
- thumbRect.move(scrollbar.width() - scrollbarThickness(parentStyleContext.get(), orientation), 0);
- else
- thumbRect.move(0, scrollbar.height() - scrollbarThickness(parentStyleContext.get(), orientation));
+ bool isIndicator = m_usesOverlayScrollbars && scrollbar.hoveredPart() == NoPart;
+ if (scrollbar.orientation() == VerticalScrollbar) {
+ int sliderWidth = sliderGadget->preferredSize().width();
+ contentsRect.move(isIndicator ? contentsRect.width() - sliderWidth : 0, thumbPosition(scrollbar));
+ contentsRect.setWidth(sliderWidth);
+ contentsRect.setHeight(thumbSize);
+ } else {
+ int sliderHeight = sliderGadget->preferredSize().height();
+ contentsRect.move(thumbPosition(scrollbar), isIndicator ? contentsRect.height() - sliderHeight : 0);
+ contentsRect.setWidth(thumbSize);
+ contentsRect.setHeight(sliderHeight);
+ }
+ if (contentsRect.intersects(damageRect))
+ sliderGadget->render(graphicsContext.platformContext()->cr(), contentsRect);
}
- adjustRectAccordingToMargin(styleContext.get(), thumbRect);
- gtk_render_slider(styleContext.get(), context.platformContext()->cr(), thumbRect.x(), thumbRect.y(), thumbRect.width(), thumbRect.height(),
- orientation == VerticalScrollbar ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
+
+ if (opacity != 1) {
+ graphicsContext.endTransparencyLayer();
+ graphicsContext.restore();
+ }
+
+ return true;
}
-
-void ScrollbarThemeGtk::paintButton(GraphicsContext& context, Scrollbar& scrollbar, const IntRect& rect, ScrollbarPart part)
+#else
+static void paintStepper(GtkStyleContext* parentContext, GraphicsContext& context, Scrollbar& scrollbar, const IntRect& rect, ScrollbarPart part)
{
ScrollbarOrientation orientation = scrollbar.orientation();
- GRefPtr<GtkStyleContext> parentStyleContext = getOrCreateStyleContext(&scrollbar, StyleContextMode::Paint);
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(parentStyleContext.get(), "contents");
- GRefPtr<GtkStyleContext> styleContext = createChildStyleContext(contentsStyleContext.get(), "button");
+ GRefPtr<GtkStyleContext> styleContext = createChildStyleContext(parentContext, "button");
unsigned flags = 0;
if ((BackButtonStartPart == part && scrollbar.currentPos())
@@ -394,9 +609,7 @@
gtk_style_context_get_style(styleContext.get(), "arrow-scaling", &arrowScaling, nullptr);
double arrowSize = std::min(rect.width(), rect.height()) * arrowScaling;
- FloatPoint arrowPoint(
- rect.x() + (rect.width() - arrowSize) / 2,
- rect.y() + (rect.height() - arrowSize) / 2);
+ FloatPoint arrowPoint(rect.x() + (rect.width() - arrowSize) / 2, rect.y() + (rect.height() - arrowSize) / 2);
if (flags & GTK_STATE_FLAG_ACTIVE) {
gint arrowDisplacementX, arrowDisplacementY;
@@ -413,18 +626,21 @@
gtk_render_arrow(styleContext.get(), context.platformContext()->cr(), angle, arrowPoint.x(), arrowPoint.y(), arrowSize);
}
+static void adjustRectAccordingToMargin(GtkStyleContext* context, IntRect& rect)
+{
+ GtkBorder margin;
+ gtk_style_context_get_margin(context, gtk_style_context_get_state(context), &margin);
+ rect.move(margin.left, margin.top);
+ rect.contract(margin.left + margin.right, margin.top + margin.bottom);
+}
+
bool ScrollbarThemeGtk::paint(Scrollbar& scrollbar, GraphicsContext& graphicsContext, const IntRect& damageRect)
{
if (graphicsContext.paintingDisabled())
return false;
- double opacity = scrollbar.hoveredPart() == NoPart ? scrollbar.opacity() : 1;
- if (!opacity)
- return true;
+ GRefPtr<GtkStyleContext> styleContext = createStyleContext(&scrollbar);
- // Cache a new GtkStyleContext for the duration of this scope.
- TemporaryChange<GRefPtr<GtkStyleContext>> tempStyleContext(m_cachedStyleContext, getOrCreateStyleContext(&scrollbar, StyleContextMode::Paint));
-
// Create the ScrollbarControlPartMask based on the damageRect
ScrollbarControlPartMask scrollMask = NoPart;
@@ -451,7 +667,9 @@
if (damageRect.intersects(trackPaintRect))
scrollMask |= TrackBGPart;
- if (troughUnderSteppers(scrollbar) && (scrollMask & BackButtonStartPart
+ gboolean troughUnderSteppers;
+ gtk_style_context_get_style(styleContext.get(), "trough-under-steppers", &troughUnderSteppers, nullptr);
+ if (troughUnderSteppers && (scrollMask & BackButtonStartPart
|| scrollMask & BackButtonEndPart
|| scrollMask & ForwardButtonStartPart
|| scrollMask & ForwardButtonEndPart))
@@ -460,63 +678,71 @@
IntRect currentThumbRect;
if (hasThumb(scrollbar)) {
IntRect track = trackRect(scrollbar, false);
- currentThumbRect = thumbRect(scrollbar, track);
+ IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, track);
+ int thumbFat;
+ gtk_style_context_get_style(styleContext.get(), "slider-width", &thumbFat, nullptr);
+ if (scrollbar.orientation() == HorizontalScrollbar)
+ currentThumbRect = IntRect(trackRect.x() + thumbPosition(scrollbar), trackRect.y() + (trackRect.height() - thumbFat) / 2, thumbLength(scrollbar), thumbFat);
+ else
+ currentThumbRect = IntRect(trackRect.x() + (trackRect.width() - thumbFat) / 2, trackRect.y() + thumbPosition(scrollbar), thumbFat, thumbLength(scrollbar));
if (damageRect.intersects(currentThumbRect))
scrollMask |= ThumbPart;
}
- if (m_usesOverlayScrollbars) {
- // FIXME: Remove this check once 3.20 is released.
-#if GTK_CHECK_VERSION(3, 19, 8)
- unsigned flags = 0;
- if (scrollbar.hoveredPart() != NoPart)
- flags |= GTK_STATE_FLAG_PRELIGHT;
- if (scrollbar.pressedPart() != NoPart)
- flags |= GTK_STATE_FLAG_ACTIVE;
- double styleOpacity;
- gtk_style_context_set_state(m_cachedStyleContext.get(), static_cast<GtkStateFlags>(flags));
- gtk_style_context_get(m_cachedStyleContext.get(), gtk_style_context_get_state(m_cachedStyleContext.get()), "opacity", &styleOpacity, nullptr);
- opacity *= styleOpacity;
-#else
- opacity *= scrollbar.hoveredPart() == NoPart ? 0.4 : 0.7;
-#endif
- }
- if (!opacity || scrollMask == NoPart)
+ if (scrollMask == NoPart)
return true;
- if (opacity != 1) {
- graphicsContext.save();
- graphicsContext.clip(damageRect);
- graphicsContext.beginTransparencyLayer(opacity);
- }
+ ScrollbarControlPartMask allButtons = BackButtonStartPart | BackButtonEndPart | ForwardButtonStartPart | ForwardButtonEndPart;
- ScrollbarControlPartMask allButtons = BackButtonStartPart | BackButtonEndPart | ForwardButtonStartPart | ForwardButtonEndPart;
+ // Paint the track background. If the trough-under-steppers property is true, this
+ // should be the full size of the scrollbar, but if is false, it should only be the
+ // track rect.
+ GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(styleContext.get(), "trough");
if (scrollMask & TrackBGPart || scrollMask & ThumbPart || scrollMask & allButtons) {
- paintScrollbarBackground(graphicsContext, scrollbar);
- paintTrackBackground(graphicsContext, scrollbar, trackPaintRect);
+ IntRect fullScrollbarRect = trackPaintRect;
+ if (troughUnderSteppers)
+ fullScrollbarRect = scrollbar.frameRect();
+
+ IntRect adjustedRect = fullScrollbarRect;
+ adjustRectAccordingToMargin(styleContext.get(), adjustedRect);
+ gtk_render_background(styleContext.get(), graphicsContext.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
+ gtk_render_frame(styleContext.get(), graphicsContext.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
+
+ adjustedRect = fullScrollbarRect;
+ adjustRectAccordingToMargin(troughStyleContext.get(), adjustedRect);
+ gtk_render_background(troughStyleContext.get(), graphicsContext.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
+ gtk_render_frame(troughStyleContext.get(), graphicsContext.platformContext()->cr(), adjustedRect.x(), adjustedRect.y(), adjustedRect.width(), adjustedRect.height());
}
// Paint the back and forward buttons.
if (scrollMask & BackButtonStartPart)
- paintButton(graphicsContext, scrollbar, backButtonStartPaintRect, BackButtonStartPart);
+ paintStepper(styleContext.get(), graphicsContext, scrollbar, backButtonStartPaintRect, BackButtonStartPart);
if (scrollMask & BackButtonEndPart)
- paintButton(graphicsContext, scrollbar, backButtonEndPaintRect, BackButtonEndPart);
+ paintStepper(styleContext.get(), graphicsContext, scrollbar, backButtonEndPaintRect, BackButtonEndPart);
if (scrollMask & ForwardButtonStartPart)
- paintButton(graphicsContext, scrollbar, forwardButtonStartPaintRect, ForwardButtonStartPart);
+ paintStepper(styleContext.get(), graphicsContext, scrollbar, forwardButtonStartPaintRect, ForwardButtonStartPart);
if (scrollMask & ForwardButtonEndPart)
- paintButton(graphicsContext, scrollbar, forwardButtonEndPaintRect, ForwardButtonEndPart);
+ paintStepper(styleContext.get(), graphicsContext, scrollbar, forwardButtonEndPaintRect, ForwardButtonEndPart);
// Paint the thumb.
- if (scrollMask & ThumbPart)
- paintThumb(graphicsContext, scrollbar, currentThumbRect);
+ if (scrollMask & ThumbPart) {
+ GRefPtr<GtkStyleContext> thumbStyleContext = createChildStyleContext(troughStyleContext.get(), "slider");
+ unsigned flags = 0;
+ if (scrollbar.pressedPart() == ThumbPart)
+ flags |= GTK_STATE_FLAG_ACTIVE;
+ if (scrollbar.hoveredPart() == ThumbPart)
+ flags |= GTK_STATE_FLAG_PRELIGHT;
+ gtk_style_context_set_state(thumbStyleContext.get(), static_cast<GtkStateFlags>(flags));
- if (opacity != 1) {
- graphicsContext.endTransparencyLayer();
- graphicsContext.restore();
+ IntRect thumbRect(currentThumbRect);
+ adjustRectAccordingToMargin(thumbStyleContext.get(), thumbRect);
+ gtk_render_slider(thumbStyleContext.get(), graphicsContext.platformContext()->cr(), thumbRect.x(), thumbRect.y(), thumbRect.width(), thumbRect.height(),
+ scrollbar.orientation() == VerticalScrollbar ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
}
return true;
}
+#endif // GTK_CHECK_VERSION(3, 20, 0)
ScrollbarButtonPressAction ScrollbarThemeGtk::handleMousePressEvent(Scrollbar&, const PlatformMouseEvent& event, ScrollbarPart pressedPart)
{
@@ -539,197 +765,93 @@
return ScrollbarButtonPressAction::None;
}
-int ScrollbarThemeGtk::scrollbarThickness(GtkStyleContext* styleContext, ScrollbarOrientation orientation)
+#if GTK_CHECK_VERSION(3, 20, 0)
+int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize)
{
- GtkBorder troughBorder;
-#if GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(styleContext, "contents");
- GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(contentsStyleContext.get(), "trough");
- GRefPtr<GtkStyleContext> sliderStyleContext = createChildStyleContext(troughStyleContext.get(), "slider");
- int thumbFat = thumbFatness(sliderStyleContext.get(), orientation);
- getTroughBorder(troughStyleContext.get(), &troughBorder);
- // Since GTK+ 3.19 the scrollbar can have its own border too.
- GtkBorder border;
- gtk_style_context_get_border(styleContext, gtk_style_context_get_state(styleContext), &border);
- troughBorder.left += border.left;
- troughBorder.right += border.right;
- troughBorder.top += border.top;
- troughBorder.bottom += border.bottom;
-#else
- int thumbFat = thumbFatness(styleContext, orientation);
- getTroughBorder(styleContext, &troughBorder);
-#endif
- if (orientation == VerticalScrollbar)
- return thumbFat + troughBorder.left + troughBorder.right;
- return thumbFat + troughBorder.top + troughBorder.bottom;
-}
+ RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", GTK_STATE_FLAG_PRELIGHT, { "vertical", "right", "hovering" } };
+ if (m_usesOverlayScrollbars)
+ info.classList.append("overlay-indicator");
+ auto scrollbarGadget = RenderThemeGadget::create(info);
+ info.type = RenderThemeGadget::Type::Generic;
+ info.name = "contents";
+ info.state = GTK_STATE_FLAG_NORMAL;
+ info.classList.clear();
+ Vector<RenderThemeGadget::Info> children;
+ auto steppers = static_cast<RenderThemeScrollbarGadget*>(scrollbarGadget.get())->steppers();
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward))
+ children.append({ RenderThemeGadget::Type::Generic, "button", GTK_STATE_FLAG_NORMAL, { "up" } });
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward))
+ children.append({ RenderThemeGadget::Type::Generic, "button", GTK_STATE_FLAG_NORMAL, { "down" } });
+ unsigned troughPositon = children.size();
+ children.append({ RenderThemeGadget::Type::Generic, "trough", GTK_STATE_FLAG_PRELIGHT, { } });
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward))
+ children.append({ RenderThemeGadget::Type::Generic, "button", GTK_STATE_FLAG_NORMAL, { "up" } });
+ if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward))
+ children.append({ RenderThemeGadget::Type::Generic, "button", GTK_STATE_FLAG_NORMAL, { "down" } });
+ auto contentsGadget = std::make_unique<RenderThemeBoxGadget>(info, children, scrollbarGadget.get());
+ info.name = "slider";
+ auto sliderGadget = RenderThemeGadget::create(info, contentsGadget->child(troughPositon));
+ IntSize preferredSize = scrollbarGadget->preferredSize();
+ preferredSize += contentsGadget->preferredSize();
+ preferredSize += sliderGadget->preferredSize();
-int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize)
-{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext();
- return scrollbarThickness(styleContext.get());
+ return preferredSize.width();
}
-
-IntSize ScrollbarThemeGtk::buttonSize(Scrollbar& scrollbar, ScrollbarPart buttonPart)
-{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
-#if GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(styleContext.get(), "contents");
- GRefPtr<GtkStyleContext> buttonStyleContext = createChildStyleContext(contentsStyleContext.get(), "button");
- switch (buttonPart) {
- case BackButtonStartPart:
- case ForwardButtonStartPart:
- gtk_style_context_add_class(buttonStyleContext.get(), "up");
- break;
- case BackButtonEndPart:
- case ForwardButtonEndPart:
- gtk_style_context_add_class(buttonStyleContext.get(), "down");
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- int minWidth = 0, minHeight = 0;
- gtk_style_context_get(buttonStyleContext.get(), gtk_style_context_get_state(buttonStyleContext.get()),
- "min-width", &minWidth, "min-height", &minHeight, nullptr);
- return IntSize(minWidth, minHeight);
#else
- UNUSED_PARAM(buttonPart);
- int stepperSize;
- gtk_style_context_get_style(styleContext.get(), "stepper-size", &stepperSize, nullptr);
- if (scrollbar.orientation() == VerticalScrollbar)
- return IntSize(thumbFatness(scrollbar), stepperSize);
-
- // HorizontalScrollbar
- return IntSize(stepperSize, thumbFatness(scrollbar));
-#endif
-}
-
-int ScrollbarThemeGtk::stepperSize(Scrollbar& scrollbar, ScrollbarPart buttonPart)
+int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize)
{
- IntSize size = buttonSize(scrollbar, buttonPart);
- return scrollbar.orientation() == VerticalScrollbar ? size.height() : size.width();
+ int thumbFat, troughBorderWidth;
+ gtk_style_context_get_style(createStyleContext().get(), "slider-width", &thumbFat, "trough-border", &troughBorderWidth, nullptr);
+ return thumbFat + 2 * troughBorderWidth;
}
+#endif // GTK_CHECK_VERSION(3, 20, 0)
-void ScrollbarThemeGtk::getStepperSpacing(Scrollbar& scrollbar, ScrollbarPart buttonPart, GtkBorder* margin)
+#if GTK_CHECK_VERSION(3, 20, 0)
+int ScrollbarThemeGtk::minimumThumbLength(Scrollbar& scrollbar)
{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
-#if GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(styleContext.get(), "contents");
- GRefPtr<GtkStyleContext> buttonStyleContext = createChildStyleContext(contentsStyleContext.get(), "button");
- switch (buttonPart) {
- case BackButtonStartPart:
- case ForwardButtonStartPart:
- gtk_style_context_add_class(buttonStyleContext.get(), "up");
- break;
- case BackButtonEndPart:
- case ForwardButtonEndPart:
- gtk_style_context_add_class(buttonStyleContext.get(), "down");
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- gtk_style_context_get_margin(buttonStyleContext.get(), gtk_style_context_get_state(buttonStyleContext.get()), margin);
-#else
- UNUSED_PARAM(buttonPart);
- int stepperSpacing = 0;
- gtk_style_context_get_style(styleContext.get(), "stepper-spacing", &stepperSpacing, nullptr);
- margin->left = margin->right = margin->top = margin->bottom = stepperSpacing;
-#endif
+ RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", GTK_STATE_FLAG_PRELIGHT, { "vertical", "right", "hovering" } };
+ if (m_usesOverlayScrollbars)
+ info.classList.append("overlay-indicator");
+ auto scrollbarGadget = RenderThemeGadget::create(info);
+ info.type = RenderThemeGadget::Type::Generic;
+ info.name = "contents";
+ info.state = GTK_STATE_FLAG_NORMAL;
+ info.classList.clear();
+ Vector<RenderThemeGadget::Info> children = {{ RenderThemeGadget::Type::Generic, "trough", GTK_STATE_FLAG_PRELIGHT, { } } };
+ auto contentsGadget = std::make_unique<RenderThemeBoxGadget>(info, children, scrollbarGadget.get());
+ info.name = "slider";
+ IntSize minSize = RenderThemeGadget::create(info, contentsGadget->child(0))->minimumSize();
+ return scrollbar.orientation() == VerticalScrollbar ? minSize.height() : minSize.width();
}
-
-bool ScrollbarThemeGtk::troughUnderSteppers(Scrollbar& scrollbar)
-{
-#if !GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
- gboolean underSteppers;
- gtk_style_context_get_style(styleContext.get(), "trough-under-steppers", &underSteppers, nullptr);
- return underSteppers;
#else
- UNUSED_PARAM(scrollbar);
- // This is now ignored by GTK+ and considered always true.
- return true;
-#endif
-}
int ScrollbarThemeGtk::minimumThumbLength(Scrollbar& scrollbar)
{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
int minThumbLength = 0;
-#if GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(styleContext.get(), "contents");
- GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(contentsStyleContext.get(), "trough");
- GRefPtr<GtkStyleContext> sliderStyleContext = createChildStyleContext(troughStyleContext.get(), "slider");
- gtk_style_context_get(sliderStyleContext.get(), gtk_style_context_get_state(sliderStyleContext.get()),
- scrollbar.orientation() == VerticalScrollbar ? "min-height" : "min-width", &minThumbLength, nullptr);
-#else
- gtk_style_context_get_style(styleContext.get(), "min-slider-length", &minThumbLength, nullptr);
-#endif
+ gtk_style_context_get_style(createStyleContext(&scrollbar).get(), "min-slider-length", &minThumbLength, nullptr);
return minThumbLength;
}
+#endif
-int ScrollbarThemeGtk::thumbFatness(GtkStyleContext* styleContext, ScrollbarOrientation orientation)
+#else // GTK_API_VERSION_2
+bool ScrollbarThemeGtk::hasThumb(Scrollbar&)
{
- int thumbFat = 0;
-#if GTK_CHECK_VERSION(3, 19, 11)
- gtk_style_context_get(styleContext, gtk_style_context_get_state(styleContext),
- orientation == VerticalScrollbar ? "min-width" : "min-height", &thumbFat, nullptr);
- GtkBorder margin;
- gtk_style_context_get_margin(styleContext, gtk_style_context_get_state(styleContext), &margin);
- GtkBorder border;
- gtk_style_context_get_border(styleContext, gtk_style_context_get_state(styleContext), &border);
- if (orientation == VerticalScrollbar)
- thumbFat += margin.left + margin.right + border.left + border.right;
- else
- thumbFat += margin.top + margin.bottom + border.top + border.bottom;
-#else
- UNUSED_PARAM(orientation);
- gtk_style_context_get_style(styleContext, "slider-width", &thumbFat, nullptr);
-#endif
- return thumbFat;
+ return false;
}
-int ScrollbarThemeGtk::thumbFatness(Scrollbar& scrollbar)
+IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar&, ScrollbarPart, bool)
{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
-#if GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(styleContext.get(), "contents");
- GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(contentsStyleContext.get(), "trough");
- GRefPtr<GtkStyleContext> sliderStyleContext = createChildStyleContext(troughStyleContext.get(), "slider");
- return thumbFatness(sliderStyleContext.get(), scrollbar.orientation());
-#else
- return thumbFatness(styleContext.get(), scrollbar.orientation());
-#endif
+ return IntRect();
}
-void ScrollbarThemeGtk::getTroughBorder(GtkStyleContext* styleContext, GtkBorder* border)
+IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar&, ScrollbarPart, bool)
{
-#if GTK_CHECK_VERSION(3, 19, 11)
- gtk_style_context_get_border(styleContext, gtk_style_context_get_state(styleContext), border);
-#else
- int troughBorderWidth = 0;
- gtk_style_context_get_style(styleContext, "trough-border", &troughBorderWidth, nullptr);
- border->top = border->bottom = border->left = border->right = troughBorderWidth;
-#endif
+ return IntRect();
}
-void ScrollbarThemeGtk::getTroughBorder(Scrollbar& scrollbar, GtkBorder* border)
+IntRect ScrollbarThemeGtk::trackRect(Scrollbar&, bool)
{
- GRefPtr<GtkStyleContext> styleContext = getOrCreateStyleContext(&scrollbar);
-#if GTK_CHECK_VERSION(3, 19, 11)
- GRefPtr<GtkStyleContext> contentsStyleContext = createChildStyleContext(styleContext.get(), "contents");
- GRefPtr<GtkStyleContext> troughStyleContext = createChildStyleContext(contentsStyleContext.get(), "trough");
- getTroughBorder(troughStyleContext.get(), border);
- // Since GTK+ 3.19 the scrollbar can have its own border too.
- GtkBorder scrollbarBorder;
- gtk_style_context_get_border(styleContext.get(), gtk_style_context_get_state(styleContext.get()), &scrollbarBorder);
- border->left += scrollbarBorder.left;
- border->right += scrollbarBorder.right;
- border->top += scrollbarBorder.top;
- border->bottom += scrollbarBorder.bottom;
-#else
- getTroughBorder(styleContext.get(), border);
-#endif
+ return IntRect();
}
-
#endif // GTK_API_VERSION_2
}