Title: [199344] trunk/Source/WebCore
Revision
199344
Author
[email protected]
Date
2016-04-12 05:42:57 -0700 (Tue, 12 Apr 2016)

Log Message

[GTK] Rework scrollbars theming code for GTK+ 3.20
https://bugs.webkit.org/show_bug.cgi?id=156462

Reviewed by Michael Catanzaro.

In r199292, we reworked the theming code to ensure it works with the new GTK+ CSS theming system. The same is
needed for scrollbars, this patch uses the RenderThemeGadget classes introduced in r199292 to render the native
scrollbars. The code is now split in 3 parts: stub methods for GTK+2 (since this file is compiled for
WebCoreGTK, but not used), the implementation for GTK+ < 3.20 and the implementation for GTK+ >= 3.20. This
reduces the amount of ifdefed code, and ensures that changes in new code don't break the rendering with older
versions of GTK+. I noticed that we were overriding both, the specific paint methods to render scrollbars
parts and the global paint method that renders all the scrollbar parts. We don't really need the specific paint
methods, so I've removed the implemention leaving only the paint method. This also allows us to get rid of the
GtkStyleContext cache.

* platform/gtk/RenderThemeGadget.cpp:
(WebCore::RenderThemeGadget::create): Handle scrollbars gadgets.
(WebCore::appendElementToPath): In case of scrollbar gadget, use the scrollbar GType when creating the path to
be able to get non-CSS style properties.
(WebCore::RenderThemeGadget::opacity): Add method to get the opacity CSS style property.
(WebCore::RenderThemeScrollbarGadget::RenderThemeScrollbarGadget): Initialize m_steppers option set with the
steppers used by the theme.
* platform/gtk/RenderThemeGadget.h:
* platform/gtk/ScrollbarThemeGtk.cpp:
(WebCore::themeChangedCallback):
(WebCore::ScrollbarThemeGtk::ScrollbarThemeGtk):
(WebCore::createStyleContext):
(WebCore::createChildStyleContext):
(WebCore::ScrollbarThemeGtk::themeChanged):
(WebCore::ScrollbarThemeGtk::updateThemeProperties):
(WebCore::scrollbarPartStateFlags):
(WebCore::scrollbarGadgetForLayout):
(WebCore::contentsGadgetForLayout):
(WebCore::ScrollbarThemeGtk::trackRect):
(WebCore::ScrollbarThemeGtk::hasThumb):
(WebCore::ScrollbarThemeGtk::backButtonRect):
(WebCore::ScrollbarThemeGtk::forwardButtonRect):
(WebCore::ScrollbarThemeGtk::paint):
(WebCore::paintStepper):
(WebCore::adjustRectAccordingToMargin):
(WebCore::ScrollbarThemeGtk::scrollbarThickness):
(WebCore::ScrollbarThemeGtk::minimumThumbLength):
* platform/gtk/ScrollbarThemeGtk.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (199343 => 199344)


--- trunk/Source/WebCore/ChangeLog	2016-04-12 12:21:57 UTC (rev 199343)
+++ trunk/Source/WebCore/ChangeLog	2016-04-12 12:42:57 UTC (rev 199344)
@@ -1,3 +1,49 @@
+2016-04-12  Carlos Garcia Campos  <[email protected]>
+
+        [GTK] Rework scrollbars theming code for GTK+ 3.20
+        https://bugs.webkit.org/show_bug.cgi?id=156462
+
+        Reviewed by Michael Catanzaro.
+
+        In r199292, we reworked the theming code to ensure it works with the new GTK+ CSS theming system. The same is
+        needed for scrollbars, this patch uses the RenderThemeGadget classes introduced in r199292 to render the native
+        scrollbars. The code is now split in 3 parts: stub methods for GTK+2 (since this file is compiled for
+        WebCoreGTK, but not used), the implementation for GTK+ < 3.20 and the implementation for GTK+ >= 3.20. This
+        reduces the amount of ifdefed code, and ensures that changes in new code don't break the rendering with older
+        versions of GTK+. I noticed that we were overriding both, the specific paint methods to render scrollbars
+        parts and the global paint method that renders all the scrollbar parts. We don't really need the specific paint
+        methods, so I've removed the implemention leaving only the paint method. This also allows us to get rid of the
+        GtkStyleContext cache.
+
+        * platform/gtk/RenderThemeGadget.cpp:
+        (WebCore::RenderThemeGadget::create): Handle scrollbars gadgets.
+        (WebCore::appendElementToPath): In case of scrollbar gadget, use the scrollbar GType when creating the path to
+        be able to get non-CSS style properties.
+        (WebCore::RenderThemeGadget::opacity): Add method to get the opacity CSS style property.
+        (WebCore::RenderThemeScrollbarGadget::RenderThemeScrollbarGadget): Initialize m_steppers option set with the
+        steppers used by the theme.
+        * platform/gtk/RenderThemeGadget.h:
+        * platform/gtk/ScrollbarThemeGtk.cpp:
+        (WebCore::themeChangedCallback):
+        (WebCore::ScrollbarThemeGtk::ScrollbarThemeGtk):
+        (WebCore::createStyleContext):
+        (WebCore::createChildStyleContext):
+        (WebCore::ScrollbarThemeGtk::themeChanged):
+        (WebCore::ScrollbarThemeGtk::updateThemeProperties):
+        (WebCore::scrollbarPartStateFlags):
+        (WebCore::scrollbarGadgetForLayout):
+        (WebCore::contentsGadgetForLayout):
+        (WebCore::ScrollbarThemeGtk::trackRect):
+        (WebCore::ScrollbarThemeGtk::hasThumb):
+        (WebCore::ScrollbarThemeGtk::backButtonRect):
+        (WebCore::ScrollbarThemeGtk::forwardButtonRect):
+        (WebCore::ScrollbarThemeGtk::paint):
+        (WebCore::paintStepper):
+        (WebCore::adjustRectAccordingToMargin):
+        (WebCore::ScrollbarThemeGtk::scrollbarThickness):
+        (WebCore::ScrollbarThemeGtk::minimumThumbLength):
+        * platform/gtk/ScrollbarThemeGtk.h:
+
 2016-03-17  Sergio Villar Senin  <[email protected]>
 
         [css-grid] Add parsing support for <auto-repeat> syntax

Modified: trunk/Source/WebCore/platform/gtk/RenderThemeGadget.cpp (199343 => 199344)


--- trunk/Source/WebCore/platform/gtk/RenderThemeGadget.cpp	2016-04-12 12:21:57 UTC (rev 199343)
+++ trunk/Source/WebCore/platform/gtk/RenderThemeGadget.cpp	2016-04-12 12:42:57 UTC (rev 199344)
@@ -47,6 +47,8 @@
         return std::make_unique<RenderThemeArrowGadget>(info, parent, siblings, position);
     case RenderThemeGadget::Type::Icon:
         return std::make_unique<RenderThemeIconGadget>(info, parent, siblings, position);
+    case RenderThemeGadget::Type::Scrollbar:
+        return std::make_unique<RenderThemeScrollbarGadget>(info, parent, siblings, position);
     }
 
     ASSERT_NOT_REACHED();
@@ -65,7 +67,8 @@
 
 static void appendElementToPath(GtkWidgetPath* path, const RenderThemeGadget::Info& info)
 {
-    gtk_widget_path_append_type(path, G_TYPE_NONE);
+    // Scrollbars need to use its GType to be able to get non-CSS style properties.
+    gtk_widget_path_append_type(path, info.type == RenderThemeGadget::Type::Scrollbar ? GTK_TYPE_SCROLLBAR : G_TYPE_NONE);
     gtk_widget_path_iter_set_object_name(path, -1, info.name);
     for (const auto* className : info.classList)
         gtk_widget_path_iter_add_class(path, -1, className);
@@ -136,6 +139,13 @@
     return returnValue;
 }
 
+double RenderThemeGadget::opacity() const
+{
+    double returnValue;
+    gtk_style_context_get(m_context.get(), gtk_style_context_get_state(m_context.get()), "opacity", &returnValue, nullptr);
+    return returnValue;
+}
+
 IntSize RenderThemeGadget::minimumSize() const
 {
     int width, height;
@@ -322,6 +332,22 @@
     return IntSize(m_iconSize, m_iconSize);
 }
 
+RenderThemeScrollbarGadget::RenderThemeScrollbarGadget(const RenderThemeGadget::Info& info, RenderThemeGadget* parent, const Vector<RenderThemeGadget::Info> siblings, unsigned position)
+    : RenderThemeGadget(info, parent, siblings, position)
+{
+    gboolean hasBackward, hasForward, hasSecondaryBackward, hasSecondaryForward;
+    gtk_style_context_get_style(m_context.get(), "has-backward-stepper", &hasBackward, "has-forward-stepper", &hasForward,
+        "has-secondary-backward-stepper", &hasSecondaryBackward, "has-secondary-forward-stepper", &hasSecondaryForward, nullptr);
+    if (hasBackward)
+        m_steppers |= Steppers::Backward;
+    if (hasForward)
+        m_steppers |= Steppers::Forward;
+    if (hasSecondaryBackward)
+        m_steppers |= Steppers::SecondaryBackward;
+    if (hasSecondaryForward)
+        m_steppers |= Steppers::SecondaryForward;
+}
+
 } // namespace WebCore
 
 #endif // GTK_CHECK_VERSION(3, 20, 0)

Modified: trunk/Source/WebCore/platform/gtk/RenderThemeGadget.h (199343 => 199344)


--- trunk/Source/WebCore/platform/gtk/RenderThemeGadget.h	2016-04-12 12:21:57 UTC (rev 199343)
+++ trunk/Source/WebCore/platform/gtk/RenderThemeGadget.h	2016-04-12 12:42:57 UTC (rev 199344)
@@ -31,6 +31,7 @@
 
 #include "Color.h"
 #include "IntSize.h"
+#include <wtf/OptionSet.h>
 #include <wtf/Vector.h>
 #include <wtf/glib/GRefPtr.h>
 #include <wtf/text/CString.h>
@@ -48,7 +49,8 @@
         Check,
         Radio,
         Arrow,
-        Icon
+        Icon,
+        Scrollbar
     };
 
     struct Info {
@@ -71,6 +73,7 @@
     GtkBorder contentsBox() const;
     Color color() const;
     Color backgroundColor() const;
+    double opacity() const;
 
 protected:
     GtkStyleContext* context() const { return m_context.get(); }
@@ -144,6 +147,22 @@
     unsigned m_iconSize { 0 };
 };
 
+class RenderThemeScrollbarGadget final : public RenderThemeGadget {
+public:
+    RenderThemeScrollbarGadget(const Info&, RenderThemeGadget* parent, const Vector<RenderThemeGadget::Info> siblings, unsigned position);
+
+    enum class Steppers {
+        Backward = 1 << 0,
+        Forward = 1 << 1,
+        SecondaryBackward = 1 << 2,
+        SecondaryForward = 1 << 3
+    };
+    OptionSet<Steppers> steppers() const { return m_steppers; };
+
+private:
+    OptionSet<Steppers> m_steppers;
+};
+
 } // namespace WebCore
 
 #endif // GTK_CHECK_VERSION(3, 20, 0)

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
 
 }

Modified: trunk/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h (199343 => 199344)


--- trunk/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h	2016-04-12 12:21:57 UTC (rev 199343)
+++ trunk/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h	2016-04-12 12:42:57 UTC (rev 199344)
@@ -46,13 +46,7 @@
 #ifndef GTK_API_VERSION_2
     ScrollbarThemeGtk();
 
-    using ScrollbarThemeComposite::thumbRect;
-    IntRect thumbRect(Scrollbar&, const IntRect& unconstrainedTrackRect);
     bool paint(Scrollbar&, GraphicsContext&, const IntRect& damageRect) override;
-    void paintScrollbarBackground(GraphicsContext&, Scrollbar&) override;
-    void paintTrackBackground(GraphicsContext&, Scrollbar&, const IntRect&) override;
-    void paintThumb(GraphicsContext&, Scrollbar&, const IntRect&) override;
-    void paintButton(GraphicsContext&, Scrollbar&, const IntRect&, ScrollbarPart) override;
     ScrollbarButtonPressAction handleMousePressEvent(Scrollbar&, const PlatformMouseEvent&, ScrollbarPart) override;
     int scrollbarThickness(ScrollbarControlSize) override;
     int minimumThumbLength(Scrollbar&) override;
@@ -67,24 +61,11 @@
 
 private:
     void updateThemeProperties();
-    enum class StyleContextMode { Layout, Paint };
-    GRefPtr<GtkStyleContext> getOrCreateStyleContext(Scrollbar* = nullptr, StyleContextMode = StyleContextMode::Layout);
 
-    IntSize buttonSize(Scrollbar&, ScrollbarPart);
-    int stepperSize(Scrollbar&, ScrollbarPart);
-    int thumbFatness(Scrollbar&);
-    int thumbFatness(GtkStyleContext*, ScrollbarOrientation = VerticalScrollbar);
-    void getTroughBorder(Scrollbar&, GtkBorder*);
-    void getTroughBorder(GtkStyleContext*, GtkBorder*);
-    int scrollbarThickness(GtkStyleContext*, ScrollbarOrientation = VerticalScrollbar);
-    void getStepperSpacing(Scrollbar&, ScrollbarPart, GtkBorder*);
-    bool troughUnderSteppers(Scrollbar&);
-
-    GRefPtr<GtkStyleContext> m_cachedStyleContext;
-    gboolean m_hasForwardButtonStartPart;
-    gboolean m_hasForwardButtonEndPart;
-    gboolean m_hasBackButtonStartPart;
-    gboolean m_hasBackButtonEndPart;
+    bool m_hasForwardButtonStartPart : 1;
+    bool m_hasForwardButtonEndPart : 1;
+    bool m_hasBackButtonStartPart : 1;
+    bool m_hasBackButtonEndPart : 1;
     bool m_usesOverlayScrollbars { false };
 #endif // GTK_API_VERSION_2
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to