Bug 1319838 - [Linux/HiDPI] Set scale factor on styles created at WidgetStyleCache, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Thu, 25 Apr 2019 13:18:49 +0000
changeset 530228 82d825105204245bb27e1258386b43c22df19774
parent 530227 54dcd30fb687720d349337ec93817a6ccb2d1079
child 530229 683bd799a54c4720de16e405cef507e267b11ec9
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1319838
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1319838 - [Linux/HiDPI] Set scale factor on styles created at WidgetStyleCache, r=jhorak Call gtk_style_context_set_scale() on styles created by WidgetStyleCache module on Gtk 3.20+ Also modify moz_gtk_widget_paint_* routines to pass the scale info to CreateStyleContext() from WidgetStyleCache. Differential Revision: https://phabricator.services.mozilla.com/D28466
widget/gtk/WidgetStyleCache.cpp
widget/gtk/WidgetStyleCache.h
widget/gtk/gtk3drawing.cpp
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -1341,28 +1341,29 @@ void ResetWidgetCache(void) {
   if (sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED]) {
     gtk_widget_destroy(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED]);
   }
 
   /* Clear already freed arrays */
   mozilla::PodArrayZero(sWidgetStorage);
 }
 
-GtkStyleContext* GetStyleContext(WidgetNodeType aNodeType,
+GtkStyleContext* GetStyleContext(WidgetNodeType aNodeType, int aScale,
                                  GtkTextDirection aDirection,
-                                 GtkStateFlags aStateFlags, StyleFlags aFlags) {
+                                 GtkStateFlags aStateFlags) {
   if (aNodeType == MOZ_GTK_DROPDOWN_ENTRY) {
     aNodeType = MOZ_GTK_ENTRY;
   }
 
   GtkStyleContext* style;
   if (gtk_check_version(3, 20, 0) != nullptr) {
     style = GetWidgetStyleInternal(aNodeType);
   } else {
     style = GetCssNodeStyleInternal(aNodeType);
+    StyleContextSetScale(style, aScale);
   }
   bool stateChanged = false;
   bool stateHasDirection = gtk_get_minor_version() >= 8;
   GtkStateFlags oldState = gtk_style_context_get_state(style);
   MOZ_ASSERT(!(aStateFlags & (STATE_FLAG_DIR_LTR | STATE_FLAG_DIR_RTL)));
   unsigned newState = aStateFlags;
   if (stateHasDirection) {
     switch (aDirection) {
@@ -1403,19 +1404,21 @@ GtkStyleContext* GetStyleContext(WidgetN
   // unnecessarily early.
   if (stateChanged && sWidgetStorage[aNodeType]) {
     gtk_style_context_invalidate(style);
   }
   return style;
 }
 
 GtkStyleContext* CreateStyleContextWithStates(WidgetNodeType aNodeType,
+                                              int aScale,
                                               GtkTextDirection aDirection,
                                               GtkStateFlags aStateFlags) {
-  GtkStyleContext* style = GetStyleContext(aNodeType, aDirection, aStateFlags);
+  GtkStyleContext* style = GetStyleContext(aNodeType, aScale, aDirection,
+                                           aStateFlags);
   GtkWidgetPath* path = gtk_widget_path_copy(gtk_style_context_get_path(style));
 
   if (gtk_check_version(3, 14, 0) == nullptr) {
     static auto sGtkWidgetPathIterGetState =
         (GtkStateFlags(*)(const GtkWidgetPath*, gint))dlsym(
             RTLD_DEFAULT, "gtk_widget_path_iter_get_state");
     static auto sGtkWidgetPathIterSetState =
         (void (*)(GtkWidgetPath*, gint, GtkStateFlags))dlsym(
@@ -1429,8 +1432,16 @@ GtkStyleContext* CreateStyleContextWithS
   }
 
   style = gtk_style_context_new();
   gtk_style_context_set_path(style, path);
   gtk_widget_path_unref(path);
 
   return style;
 }
+
+void StyleContextSetScale(GtkStyleContext *style, gint aScaleFactor) {
+  // Support HiDPI styles on Gtk 3.20+
+  static auto sGtkStyleContextSetScalePtr =
+      (void (*)(GtkStyleContext *, gint))dlsym(
+          RTLD_DEFAULT, "gtk_style_context_set_scale");
+  sGtkStyleContextSetScalePtr(style, aScaleFactor);
+}
--- a/widget/gtk/WidgetStyleCache.h
+++ b/widget/gtk/WidgetStyleCache.h
@@ -5,22 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WidgetStyleCache_h
 #define WidgetStyleCache_h
 
 #include <gtk/gtk.h>
 #include "gtkdrawing.h"
 
-typedef unsigned StyleFlags;
-enum : StyleFlags {
-  NO_STYLE_FLAGS,
-  WHATEVER_MIGHT_BE_NEEDED = 1U << 0,
-};
-
 GtkWidget* GetWidget(WidgetNodeType aNodeType);
 
 cairo_surface_t* GetWidgetIconSurface(GtkWidget* aWidgetIcon, int aScale);
 
 /*
  * Return a new style context based on aWidget, as a child of aParentStyle.
  * If aWidget still has a floating reference, then it is sunk and released.
  */
@@ -36,25 +30,28 @@ GtkStyleContext* CreateCSSNode(const cha
  * for instance GetStyleContext(MOZ_GTK_BUTTON, .., GTK_STATE_FLAG_HOVER)
  * you get "window button:hover" css selector.
  * If you want aStateFlags applied to all path elements use
  * CreateStyleContextWithStates().
  *
  * The context is owned by WidgetStyleCache. Do not unref.
  */
 GtkStyleContext* GetStyleContext(
-    WidgetNodeType aNodeType, GtkTextDirection aDirection = GTK_TEXT_DIR_NONE,
-    GtkStateFlags aStateFlags = GTK_STATE_FLAG_NORMAL,
-    StyleFlags aFlags = NO_STYLE_FLAGS);
+    WidgetNodeType aNodeType, int aScale = 1,
+    GtkTextDirection aDirection = GTK_TEXT_DIR_NONE,
+    GtkStateFlags aStateFlags = GTK_STATE_FLAG_NORMAL);
 
 /*
  * Returns a pointer to a style context for the specified node
  * and state applied to all elements at widget style path.
  *
  * The context is owned by caller and must be released by g_object_unref().
  */
 GtkStyleContext* CreateStyleContextWithStates(
-    WidgetNodeType aNodeType, GtkTextDirection aDirection = GTK_TEXT_DIR_NONE,
+    WidgetNodeType aNodeType, int aScale = 1,
+    GtkTextDirection aDirection = GTK_TEXT_DIR_NONE,
     GtkStateFlags aStateFlags = GTK_STATE_FLAG_NORMAL);
 
 void ResetWidgetCache(void);
 
+void StyleContextSetScale(GtkStyleContext *style, gint aScaleFactor);
+
 #endif  // WidgetStyleCache_h
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -633,17 +633,17 @@ static gint moz_gtk_toggle_paint(cairo_t
     state_flags =
         static_cast<GtkStateFlags>(state_flags | checkbox_check_state);
 
   if (inconsistent)
     state_flags =
         static_cast<GtkStateFlags>(state_flags | GTK_STATE_FLAG_INCONSISTENT);
 
   style = GetStyleContext(isradio ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON,
-                          direction, state_flags);
+                          state->scale, direction, state_flags);
 
   if (gtk_check_version(3, 20, 0) == nullptr) {
     gtk_render_background(style, cr, x, y, width, height);
     gtk_render_frame(style, cr, x, y, width, height);
     // Indicator is inset by the toggle's padding and border.
     gint indicator_x = x + metrics->borderAndPadding.left;
     gint indicator_y = y + metrics->borderAndPadding.top;
     gint indicator_width = metrics->minSizeWithBorder.width -
@@ -920,65 +920,67 @@ static gint moz_gtk_scrollbar_trough_pai
   GdkRectangle rect = *aRect;
   GtkStyleContext* style;
 
   if (gtk_get_minor_version() >= 20) {
     WidgetNodeType thumb = widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL
                                ? MOZ_GTK_SCROLLBAR_THUMB_VERTICAL
                                : MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
     MozGtkSize thumbSize = GetMinMarginBox(GetStyleContext(thumb));
-    style = GetStyleContext(widget, direction, state_flags);
+    style = GetStyleContext(widget, state->scale, direction, state_flags);
     MozGtkSize trackSize = GetMinContentBox(style);
     trackSize.Include(thumbSize);
     trackSize += GetMarginBorderPadding(style);
     // Gecko's trough |aRect| fills available breadth, but GTK's trough is
     // centered in the contents_gadget.  The centering here round left
     // and up, like gtk_box_gadget_allocate_child().
     if (widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL) {
       rect.x += (rect.width - trackSize.width) / 2;
       rect.width = trackSize.width;
     } else {
       rect.y += (rect.height - trackSize.height) / 2;
       rect.height = trackSize.height;
     }
   } else {
-    style = GetStyleContext(widget, direction, state_flags);
+    style = GetStyleContext(widget, state->scale, direction, state_flags);
   }
 
   moz_gtk_draw_styled_frame(style, cr, &rect, state->focused);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_scrollbar_paint(WidgetNodeType widget, cairo_t* cr,
                                     const GdkRectangle* rect,
                                     GtkWidgetState* state,
                                     GtkTextDirection direction) {
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
-  GtkStyleContext* style = GetStyleContext(widget, direction, state_flags);
+  GtkStyleContext* style = GetStyleContext(widget, state->scale, direction,
+                                           state_flags);
 
   moz_gtk_update_scrollbar_style(style, widget, direction);
 
   moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
 
   style = GetStyleContext((widget == MOZ_GTK_SCROLLBAR_HORIZONTAL)
                               ? MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL
                               : MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL,
-                          direction, state_flags);
+                          state->scale, direction, state_flags);
   moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_scrollbar_thumb_paint(WidgetNodeType widget, cairo_t* cr,
                                           const GdkRectangle* aRect,
                                           GtkWidgetState* state,
                                           GtkTextDirection direction) {
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
-  GtkStyleContext* style = GetStyleContext(widget, direction, state_flags);
+  GtkStyleContext* style = GetStyleContext(widget, state->scale, direction,
+                                           state_flags);
 
   GtkOrientation orientation = (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
                                    ? GTK_ORIENTATION_HORIZONTAL
                                    : GTK_ORIENTATION_VERTICAL;
 
   GdkRectangle rect = *aRect;
 
   const ScrollbarGTKMetrics* metrics =
@@ -992,17 +994,18 @@ static gint moz_gtk_scrollbar_thumb_pain
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_inner_spin_paint(cairo_t* cr, GdkRectangle* rect,
                                      GtkWidgetState* state,
                                      GtkTextDirection direction) {
   GtkStyleContext* style = GetStyleContext(
-      MOZ_GTK_SPINBUTTON, direction, GetStateFlagsFromGtkWidgetState(state));
+      MOZ_GTK_SPINBUTTON, state->scale, direction,
+      GetStateFlagsFromGtkWidgetState(state));
 
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
 
   /* hard code these values */
   GdkRectangle arrow_rect;
   arrow_rect.width = 6;
   arrow_rect.height = 6;
@@ -1019,28 +1022,31 @@ static gint moz_gtk_inner_spin_paint(cai
   arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2 + 3;
   gtk_render_arrow(style, cr, ARROW_DOWN, arrow_rect.x, arrow_rect.y,
                    arrow_rect.width);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_spin_paint(cairo_t* cr, GdkRectangle* rect,
+                               GtkWidgetState* state,
                                GtkTextDirection direction) {
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_SPINBUTTON, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_SPINBUTTON, state->scale,
+                                           direction);
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_spin_updown_paint(cairo_t* cr, GdkRectangle* rect,
                                       gboolean isDown, GtkWidgetState* state,
                                       GtkTextDirection direction) {
   GtkStyleContext* style = GetStyleContext(
-      MOZ_GTK_SPINBUTTON, direction, GetStateFlagsFromGtkWidgetState(state));
+      MOZ_GTK_SPINBUTTON, state->scale, direction,
+      GetStateFlagsFromGtkWidgetState(state));
 
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
 
   /* hard code these values */
   GdkRectangle arrow_rect;
   arrow_rect.width = 6;
   arrow_rect.height = 6;
@@ -1064,17 +1070,17 @@ static gint moz_gtk_scale_paint(cairo_t*
   GtkStyleContext* style;
   GtkBorder margin;
 
   moz_gtk_get_scale_metrics(flags, &min_width, &min_height);
 
   WidgetNodeType widget = (flags == GTK_ORIENTATION_HORIZONTAL)
                               ? MOZ_GTK_SCALE_TROUGH_HORIZONTAL
                               : MOZ_GTK_SCALE_TROUGH_VERTICAL;
-  style = GetStyleContext(widget, direction, state_flags);
+  style = GetStyleContext(widget, state->scale, direction, state_flags);
   gtk_style_context_get_margin(style, state_flags, &margin);
 
   // Clamp the dimension perpendicular to the direction that the slider crosses
   // to the minimum size.
   if (flags == GTK_ORIENTATION_HORIZONTAL) {
     width = rect->width - (margin.left + margin.right);
     height = min_height - (margin.top + margin.bottom);
     x = rect->x + margin.left;
@@ -1116,45 +1122,48 @@ static gint moz_gtk_scale_thumb_paint(ca
                                    &thumb_width);
     x = rect->x + (rect->width - thumb_width) / 2;
     y = rect->y;
   }
 
   WidgetNodeType widget = (flags == GTK_ORIENTATION_HORIZONTAL)
                               ? MOZ_GTK_SCALE_THUMB_HORIZONTAL
                               : MOZ_GTK_SCALE_THUMB_VERTICAL;
-  style = GetStyleContext(widget, direction, state_flags);
+  style = GetStyleContext(widget, state->scale, direction, state_flags);
   gtk_render_slider(style, cr, x, y, thumb_width, thumb_height, flags);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_gripper_paint(cairo_t* cr, GdkRectangle* rect,
                                   GtkWidgetState* state,
                                   GtkTextDirection direction) {
   GtkStyleContext* style = GetStyleContext(
-      MOZ_GTK_GRIPPER, direction, GetStateFlagsFromGtkWidgetState(state));
+      MOZ_GTK_GRIPPER, state->scale, direction,
+      GetStateFlagsFromGtkWidgetState(state));
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_hpaned_paint(cairo_t* cr, GdkRectangle* rect,
                                  GtkWidgetState* state) {
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL, GTK_TEXT_DIR_LTR,
+      GetStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL, state->scale,
+                      GTK_TEXT_DIR_LTR,
                       GetStateFlagsFromGtkWidgetState(state));
   gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_vpaned_paint(cairo_t* cr, GdkRectangle* rect,
                                  GtkWidgetState* state) {
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL, GTK_TEXT_DIR_LTR,
+      GetStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL, state->scale,
+                      GTK_TEXT_DIR_LTR,
                       GetStateFlagsFromGtkWidgetState(state));
   gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 // See gtk_entry_draw() for reference.
 static gint moz_gtk_entry_paint(cairo_t* cr, GdkRectangle* rect,
                                 GtkWidgetState* state, GtkStyleContext* style,
@@ -1195,31 +1204,33 @@ static gint moz_gtk_text_view_paint(cair
   // some themes as GtkTextView backgrounds do not typically render
   // differently with focus.
   GtkStateFlags state_flags =
       state->disabled
           ? GTK_STATE_FLAG_INSENSITIVE
           : state->focused ? GTK_STATE_FLAG_FOCUSED : GTK_STATE_FLAG_NORMAL;
 
   GtkStyleContext* style_frame =
-      GetStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction, state_flags);
+      GetStyleContext(MOZ_GTK_SCROLLED_WINDOW, state->scale, direction,
+                      state_flags);
   gtk_render_frame(style_frame, cr, aRect->x, aRect->y, aRect->width,
                    aRect->height);
 
   GdkRectangle rect = *aRect;
   InsetByBorderPadding(&rect, style_frame);
 
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_TEXT_VIEW, direction, state_flags);
+      GetStyleContext(MOZ_GTK_TEXT_VIEW, state->scale, direction, state_flags);
   gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
   // There is a separate "text" window, which usually provides the
   // background behind the text.  However, this is transparent in Ambiance
   // for GTK 3.20, in which case the MOZ_GTK_TEXT_VIEW background is
   // visible.
-  style = GetStyleContext(MOZ_GTK_TEXT_VIEW_TEXT, direction, state_flags);
+  style = GetStyleContext(MOZ_GTK_TEXT_VIEW_TEXT, state->scale, direction,
+                          state_flags);
   gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_treeview_paint(cairo_t* cr, GdkRectangle* rect,
                                    GtkWidgetState* state,
                                    GtkTextDirection direction) {
@@ -1229,27 +1240,27 @@ static gint moz_gtk_treeview_paint(cairo
   GtkStateFlags state_flags;
   GtkBorder border;
 
   /* only handle disabled and normal states, otherwise the whole background
    * area will be painted differently with other states */
   state_flags =
       state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL;
 
-  style = GetStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction);
+  style = GetStyleContext(MOZ_GTK_SCROLLED_WINDOW, state->scale, direction);
   gtk_style_context_get_border(style, state_flags, &border);
   xthickness = border.left;
   ythickness = border.top;
 
-  style_tree = GetStyleContext(MOZ_GTK_TREEVIEW_VIEW, direction);
+  style_tree = GetStyleContext(MOZ_GTK_TREEVIEW_VIEW, state->scale, direction);
   gtk_render_background(style_tree, cr, rect->x + xthickness,
                         rect->y + ythickness, rect->width - 2 * xthickness,
                         rect->height - 2 * ythickness);
 
-  style = GetStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction);
+  style = GetStyleContext(MOZ_GTK_SCROLLED_WINDOW, state->scale, direction);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_tree_header_cell_paint(cairo_t* cr, GdkRectangle* rect,
                                            GtkWidgetState* state,
                                            gboolean isSorted,
                                            GtkTextDirection direction) {
@@ -1267,17 +1278,18 @@ static gint moz_gtk_tree_header_sort_arr
   gdouble arrow_angle;
   GtkStyleContext* style;
 
   /* hard code these values */
   arrow_rect.width = 11;
   arrow_rect.height = 11;
   arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
   arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
-  style = GetStyleContext(MOZ_GTK_TREE_HEADER_SORTARROW, direction,
+  style = GetStyleContext(MOZ_GTK_TREE_HEADER_SORTARROW, state->scale,
+                          direction,
                           GetStateFlagsFromGtkWidgetState(state));
   switch (arrow_type) {
     case GTK_ARROW_LEFT:
       arrow_angle = ARROW_LEFT;
       break;
     case GTK_ARROW_RIGHT:
       arrow_angle = ARROW_RIGHT;
       break;
@@ -1319,17 +1331,18 @@ static gint moz_gtk_treeview_expander_pa
   if (expander_state == GTK_EXPANDER_EXPANDED)
     state_flags =
         static_cast<GtkStateFlags>(state_flags | checkbox_check_state);
   else
     state_flags =
         static_cast<GtkStateFlags>(state_flags & ~(checkbox_check_state));
 
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_TREEVIEW_EXPANDER, direction, state_flags);
+      GetStyleContext(MOZ_GTK_TREEVIEW_EXPANDER, state->scale, direction,
+                      state_flags);
   gtk_render_expander(style, cr, rect->x, rect->y, rect->width, rect->height);
 
   return MOZ_GTK_SUCCESS;
 }
 
 /* See gtk_separator_draw() for reference.
  */
 static gint moz_gtk_combo_box_paint(cairo_t* cr, GdkRectangle* rect,
@@ -1355,17 +1368,17 @@ static gint moz_gtk_combo_box_paint(cair
   gtk_widget_get_preferred_size(comboBoxArrow, NULL, &arrow_req);
 
   if (direction == GTK_TEXT_DIR_LTR)
     arrow_rect.x += arrow_rect.width - arrow_req.width;
   arrow_rect.width = arrow_req.width;
 
   calculate_arrow_rect(comboBoxArrow, &arrow_rect, &real_arrow_rect, direction);
 
-  style = GetStyleContext(MOZ_GTK_COMBOBOX_ARROW);
+  style = GetStyleContext(MOZ_GTK_COMBOBOX_ARROW, state->scale);
   gtk_render_arrow(style, cr, ARROW_DOWN, real_arrow_rect.x, real_arrow_rect.y,
                    real_arrow_rect.width);
 
   /* If there is no separator in the theme, there's nothing left to do. */
   GtkWidget* widget = GetWidget(MOZ_GTK_COMBOBOX_SEPARATOR);
   if (!widget) return MOZ_GTK_SUCCESS;
   style = gtk_widget_get_style_context(widget);
   gtk_style_context_get_style(style, "wide-separators", &wide_separators,
@@ -1422,17 +1435,18 @@ static gint moz_gtk_arrow_paint(cairo_t*
       break;
   }
   if (arrow_type == GTK_ARROW_NONE) return MOZ_GTK_SUCCESS;
 
   calculate_arrow_rect(GetWidget(MOZ_GTK_BUTTON_ARROW), rect, &arrow_rect,
                        direction);
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_BUTTON_ARROW, direction, state_flags);
+      GetStyleContext(MOZ_GTK_BUTTON_ARROW, state->scale, direction,
+                      state_flags);
   gtk_render_arrow(style, cr, arrow_angle, arrow_rect.x, arrow_rect.y,
                    arrow_rect.width);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_combo_box_entry_button_paint(cairo_t* cr,
                                                  GdkRectangle* rect,
                                                  GtkWidgetState* state,
@@ -1454,75 +1468,79 @@ static gint moz_gtk_combo_box_entry_butt
                                 "child-displacement-y", &y_displacement, NULL);
     arrow_rect.x += x_displacement;
     arrow_rect.y += y_displacement;
   }
 
   calculate_arrow_rect(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_ARROW), &arrow_rect,
                        &real_arrow_rect, direction);
 
-  style = GetStyleContext(MOZ_GTK_COMBOBOX_ENTRY_ARROW);
+  style = GetStyleContext(MOZ_GTK_COMBOBOX_ENTRY_ARROW, state->scale);
   gtk_render_arrow(style, cr, ARROW_DOWN, real_arrow_rect.x, real_arrow_rect.y,
                    real_arrow_rect.width);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_container_paint(cairo_t* cr, GdkRectangle* rect,
                                     GtkWidgetState* state,
                                     WidgetNodeType widget_type,
                                     GtkTextDirection direction) {
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
-  GtkStyleContext* style = GetStyleContext(widget_type, direction, state_flags);
+  GtkStyleContext* style = GetStyleContext(widget_type, state->scale,
+                                           direction, state_flags);
   /* this is for drawing a prelight box */
   if (state_flags & GTK_STATE_FLAG_PRELIGHT) {
     gtk_render_background(style, cr, rect->x, rect->y, rect->width,
                           rect->height);
   }
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_toggle_label_paint(cairo_t* cr, GdkRectangle* rect,
                                        GtkWidgetState* state, gboolean isradio,
                                        GtkTextDirection direction) {
   if (!state->focused) return MOZ_GTK_SUCCESS;
 
   GtkStyleContext* style = GetStyleContext(
       isradio ? MOZ_GTK_RADIOBUTTON_CONTAINER : MOZ_GTK_CHECKBUTTON_CONTAINER,
-      direction, GetStateFlagsFromGtkWidgetState(state));
+      state->scale, direction, GetStateFlagsFromGtkWidgetState(state));
   gtk_render_focus(style, cr, rect->x, rect->y, rect->width, rect->height);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_toolbar_paint(cairo_t* cr, GdkRectangle* rect,
+                                  GtkWidgetState* state,
                                   GtkTextDirection direction) {
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TOOLBAR, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TOOLBAR, state->scale,
+                                           direction);
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 /* See _gtk_toolbar_paint_space_line() for reference.
  */
 static gint moz_gtk_toolbar_separator_paint(cairo_t* cr, GdkRectangle* rect,
+                                            GtkWidgetState* state,
                                             GtkTextDirection direction) {
   gint separator_width;
   gint paint_width;
   gboolean wide_separators;
 
   /* Defined as constants in GTK+ 2.10.14 */
   const double start_fraction = 0.2;
   const double end_fraction = 0.8;
 
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TOOLBAR);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TOOLBAR, state->scale);
   gtk_style_context_get_style(style, "wide-separators", &wide_separators,
                               "separator-width", &separator_width, NULL);
 
-  style = GetStyleContext(MOZ_GTK_TOOLBAR_SEPARATOR, direction);
+  style = GetStyleContext(MOZ_GTK_TOOLBAR_SEPARATOR, state->scale, direction);
   if (wide_separators) {
     if (separator_width > rect->width) separator_width = rect->width;
 
     gtk_render_frame(style, cr, rect->x + (rect->width - separator_width) / 2,
                      rect->y + rect->height * start_fraction, separator_width,
                      rect->height * (end_fraction - start_fraction));
   } else {
     GtkBorder padding;
@@ -1536,65 +1554,68 @@ static gint moz_gtk_toolbar_separator_pa
                     rect->y + rect->height * start_fraction,
                     rect->x + (rect->width - paint_width) / 2,
                     rect->y + rect->height * end_fraction);
   }
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_tooltip_paint(cairo_t* cr, const GdkRectangle* aRect,
+                                  GtkWidgetState* state,
                                   GtkTextDirection direction) {
   // Tooltip widget is made in GTK3 as following tree:
   // Tooltip window
   //   Horizontal Box
   //     Icon (not supported by Firefox)
   //     Label
   // Each element can be fully styled by CSS of GTK theme.
   // We have to draw all elements with appropriate offset and right dimensions.
 
   // Tooltip drawing
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TOOLTIP, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TOOLTIP, state->scale,
+                                           direction);
   GdkRectangle rect = *aRect;
   gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
   gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height);
 
   // Horizontal Box drawing
   //
   // The box element has hard-coded 6px margin-* GtkWidget properties, which
   // are added between the window dimensions and the CSS margin box of the
   // horizontal box.  The frame of the tooltip window is drawn in the
   // 6px margin.
   // For drawing Horizontal Box we have to inset drawing area by that 6px
   // plus its CSS margin.
-  GtkStyleContext* boxStyle = GetStyleContext(MOZ_GTK_TOOLTIP_BOX, direction);
+  GtkStyleContext* boxStyle = GetStyleContext(MOZ_GTK_TOOLTIP_BOX,
+                                              state->scale, direction);
 
   rect.x += 6;
   rect.y += 6;
   rect.width -= 12;
   rect.height -= 12;
 
   InsetByMargin(&rect, boxStyle);
   gtk_render_background(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
   gtk_render_frame(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
 
   // Label drawing
   InsetByBorderPadding(&rect, boxStyle);
 
   GtkStyleContext* labelStyle =
-      GetStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL, direction);
+      GetStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL, state->scale, direction);
   moz_gtk_draw_styled_frame(labelStyle, cr, &rect, false);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_resizer_paint(cairo_t* cr, GdkRectangle* rect,
                                   GtkWidgetState* state,
                                   GtkTextDirection direction) {
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_RESIZER, GTK_TEXT_DIR_LTR,
+      GetStyleContext(MOZ_GTK_RESIZER, state->scale, GTK_TEXT_DIR_LTR,
                       GetStateFlagsFromGtkWidgetState(state));
 
   // Workaround unico not respecting the text direction for resizers.
   // See bug 1174248.
   cairo_save(cr);
   if (direction == GTK_TEXT_DIR_RTL) {
     cairo_matrix_t mat;
     cairo_matrix_init_translate(&mat, 2 * rect->x + rect->width, 0);
@@ -1604,35 +1625,41 @@ static gint moz_gtk_resizer_paint(cairo_
 
   gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height);
   cairo_restore(cr);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_frame_paint(cairo_t* cr, GdkRectangle* rect,
+                                GtkWidgetState* state,
                                 GtkTextDirection direction) {
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_FRAME, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_FRAME, state->scale,
+                                           direction);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_progressbar_paint(cairo_t* cr, GdkRectangle* rect,
+                                      GtkWidgetState* state,
                                       GtkTextDirection direction) {
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_PROGRESS_TROUGH, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_PROGRESS_TROUGH,
+                                           state->scale, direction);
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_progress_chunk_paint(cairo_t* cr, GdkRectangle* rect,
+                                         GtkWidgetState* state,
                                          GtkTextDirection direction,
                                          WidgetNodeType widget) {
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_PROGRESS_CHUNK,
+                                           state->scale, direction);
 
   if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
       widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
     /**
      * The bar's size and the bar speed are set depending of the progress'
      * size. These could also be constant for all progress bars easily.
      */
     gboolean vertical =
@@ -1708,17 +1735,17 @@ static gint moz_gtk_tab_paint(cairo_t* c
   GtkStyleContext* style;
   GdkRectangle tabRect;
   GdkRectangle focusRect;
   GdkRectangle backRect;
   int initial_gap = 0;
   bool isBottomTab = (widget == MOZ_GTK_TAB_BOTTOM);
 
   style =
-      GetStyleContext(widget, direction, GetStateFlagsFromGtkTabFlags(flags));
+      GetStyleContext(widget, state->scale, direction, GetStateFlagsFromGtkTabFlags(flags));
   tabRect = *rect;
 
   if (flags & MOZ_GTK_TAB_FIRST) {
     gtk_style_context_get_style(style, "initial-gap", &initial_gap, NULL);
     tabRect.width -= initial_gap;
 
     if (direction != GTK_TEXT_DIR_RTL) {
       tabRect.x += initial_gap;
@@ -1784,17 +1811,17 @@ static gint moz_gtk_tab_paint(cairo_t* c
       if (flags & MOZ_GTK_TAB_FIRST) {
         if (direction == GTK_TEXT_DIR_RTL)
           gap_roffset = initial_gap;
         else
           gap_loffset = initial_gap;
       }
 
       GtkStyleContext* panelStyle =
-          GetStyleContext(MOZ_GTK_TABPANELS, direction);
+          GetStyleContext(MOZ_GTK_TABPANELS, state->scale, direction);
 
       if (isBottomTab) {
         /* Draw the tab on bottom */
         focusRect.y += gap_voffset;
         focusRect.height -= gap_voffset;
 
         gtk_render_extension(style, cr, tabRect.x, tabRect.y + gap_voffset,
                              tabRect.width, tabRect.height - gap_voffset,
@@ -1867,18 +1894,20 @@ static gint moz_gtk_tab_paint(cairo_t* c
                      focusRect.height);
   }
 
   return MOZ_GTK_SUCCESS;
 }
 
 /* tab area*/
 static gint moz_gtk_tabpanels_paint(cairo_t* cr, GdkRectangle* rect,
+                                    GtkWidgetState* state,
                                     GtkTextDirection direction) {
-  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TABPANELS, direction);
+  GtkStyleContext* style = GetStyleContext(MOZ_GTK_TABPANELS, state->scale,
+                                           direction);
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   /*
    * The gap size is not needed in moz_gtk_tabpanels_paint because
    * the gap will be painted with the foreground tab in moz_gtk_tab_paint.
    *
    * However, if moz_gtk_tabpanels_paint just uses gtk_render_frame(),
    * the theme will think that there are no tabs and may draw something
    * different.Hence the trick of using two clip regions, and drawing the
@@ -1930,79 +1959,91 @@ static gint moz_gtk_tab_scroll_arrow_pai
     case GTK_ARROW_DOWN:
       arrow_angle = ARROW_DOWN;
       break;
     default:
       arrow_angle = ARROW_UP;
       break;
   }
   if (arrow_type != GTK_ARROW_NONE) {
-    style = GetStyleContext(MOZ_GTK_TAB_SCROLLARROW, direction,
+    style = GetStyleContext(MOZ_GTK_TAB_SCROLLARROW, state->scale, direction,
                             GetStateFlagsFromGtkWidgetState(state));
     gtk_render_arrow(style, cr, arrow_angle, x, y, arrow_size);
   }
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_menu_bar_paint(cairo_t* cr, GdkRectangle* rect,
+                                   GtkWidgetState* state,
                                    GtkTextDirection direction) {
   GtkStyleContext* style;
 
   GtkWidget* widget = GetWidget(MOZ_GTK_MENUBAR);
   gtk_widget_set_direction(widget, direction);
 
   style = gtk_widget_get_style_context(widget);
   gtk_style_context_save(style);
   gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
+
+  if (state->scale != 1) {
+    StyleContextSetScale(style, state->scale);
+  }
+
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_style_context_restore(style);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_menu_popup_paint(cairo_t* cr, GdkRectangle* rect,
+                                     GtkWidgetState* state,
                                      GtkTextDirection direction) {
   GtkStyleContext* style;
 
   GtkWidget* widget = GetWidget(MOZ_GTK_MENUPOPUP);
   gtk_widget_set_direction(widget, direction);
 
   // Draw a backing toplevel. This fixes themes that don't provide a menu
   // background, and depend on the GtkMenu's implementation window to provide
   // it.
   moz_gtk_window_paint(cr, rect, direction);
 
   style = gtk_widget_get_style_context(widget);
   gtk_style_context_save(style);
   gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENU);
 
+  if (state->scale != 1) {
+    StyleContextSetScale(style, state->scale);
+  }
+
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_style_context_restore(style);
 
   return MOZ_GTK_SUCCESS;
 }
 
 // See gtk_menu_item_draw() for reference.
 static gint moz_gtk_menu_separator_paint(cairo_t* cr, GdkRectangle* rect,
+                                         GtkWidgetState* state,
                                          GtkTextDirection direction) {
   GtkWidgetState defaultState = {0};
   moz_gtk_menu_item_paint(MOZ_GTK_MENUSEPARATOR, cr, rect, &defaultState,
                           direction);
 
   if (gtk_get_minor_version() >= 20) return MOZ_GTK_SUCCESS;
 
   GtkStyleContext* style;
   gboolean wide_separators;
   gint separator_height;
   gint x, y, w;
   GtkBorder padding;
 
-  style = GetStyleContext(MOZ_GTK_MENUSEPARATOR, direction);
+  style = GetStyleContext(MOZ_GTK_MENUSEPARATOR, state->scale, direction);
   gtk_style_context_get_padding(style, gtk_style_context_get_state(style),
                                 &padding);
 
   x = rect->x;
   y = rect->y;
   w = rect->width;
 
   gtk_style_context_save(style);
@@ -2033,17 +2074,18 @@ static gint moz_gtk_menu_item_paint(Widg
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
 
   // GTK versions prior to 3.8 render the background and frame only when not
   // a separator and in hover prelight.
   if (minorVersion < 8 && (widget == MOZ_GTK_MENUSEPARATOR ||
                            !(state_flags & GTK_STATE_FLAG_PRELIGHT)))
     return MOZ_GTK_SUCCESS;
 
-  GtkStyleContext* style = GetStyleContext(widget, direction, state_flags);
+  GtkStyleContext* style = GetStyleContext(widget, state->scale,
+                                           direction, state_flags);
 
   if (minorVersion < 6) {
     // GTK+ 3.4 saves the style context and adds the menubar class to
     // menubar children, but does each of these only when drawing, not
     // during layout.
     gtk_style_context_save(style);
     if (widget == MOZ_GTK_MENUBARITEM) {
       gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
@@ -2065,17 +2107,17 @@ static gint moz_gtk_menu_item_paint(Widg
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_menu_arrow_paint(cairo_t* cr, GdkRectangle* rect,
                                      GtkWidgetState* state,
                                      GtkTextDirection direction) {
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_MENUITEM, direction, state_flags);
+      GetStyleContext(MOZ_GTK_MENUITEM, state->scale, direction, state_flags);
   gtk_render_arrow(style, cr,
                    (direction == GTK_TEXT_DIR_LTR) ? ARROW_RIGHT : ARROW_LEFT,
                    rect->x, rect->y, rect->width);
   return MOZ_GTK_SUCCESS;
 }
 
 // For reference, see gtk_check_menu_item_size_allocate() in GTK versions after
 // 3.20 and gtk_real_check_menu_item_draw_indicator() in earlier versions.
@@ -2093,34 +2135,34 @@ static gint moz_gtk_check_menu_item_pain
 
   if (checked) {
     state_flags =
         static_cast<GtkStateFlags>(state_flags | checkbox_check_state);
   }
 
   bool pre_3_20 = gtk_get_minor_version() < 20;
   gint offset;
-  style = GetStyleContext(widgetType, direction);
+  style = GetStyleContext(widgetType, state->scale, direction);
   gtk_style_context_get_style(style, "indicator-size", &indicator_size,
                               "horizontal-padding", &horizontal_padding, NULL);
   if (pre_3_20) {
     GtkBorder padding;
     gtk_style_context_get_padding(style, state_flags, &padding);
     offset = horizontal_padding + padding.left + 2;
   } else {
     GdkRectangle r = {0};
     InsetByMargin(&r, style);
     InsetByBorderPadding(&r, style);
     offset = r.x;
   }
 
   bool isRadio = (widgetType == MOZ_GTK_RADIOMENUITEM);
   WidgetNodeType indicatorType = isRadio ? MOZ_GTK_RADIOMENUITEM_INDICATOR
                                          : MOZ_GTK_CHECKMENUITEM_INDICATOR;
-  style = GetStyleContext(indicatorType, direction, state_flags);
+  style = GetStyleContext(indicatorType, state->scale, direction, state_flags);
 
   if (direction == GTK_TEXT_DIR_RTL) {
     x = rect->width - indicator_size - offset;
   } else {
     x = rect->x + offset;
   }
   y = rect->y + (rect->height - indicator_size) / 2;
 
@@ -2136,46 +2178,47 @@ static gint moz_gtk_check_menu_item_pain
   }
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_info_bar_paint(cairo_t* cr, GdkRectangle* rect,
                                    GtkWidgetState* state) {
   GtkStyleContext* style =
-      GetStyleContext(MOZ_GTK_INFO_BAR, GTK_TEXT_DIR_LTR,
+      GetStyleContext(MOZ_GTK_INFO_BAR, state->scale, GTK_TEXT_DIR_LTR,
                       GetStateFlagsFromGtkWidgetState(state));
   gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
   gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
 
   return MOZ_GTK_SUCCESS;
 }
 
 static gint moz_gtk_header_bar_paint(WidgetNodeType widgetType, cairo_t* cr,
                                      GdkRectangle* rect,
                                      GtkWidgetState* state) {
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
   GtkStyleContext* style =
-      GetStyleContext(widgetType, GTK_TEXT_DIR_NONE, state_flags);
+      GetStyleContext(widgetType, state->scale, GTK_TEXT_DIR_NONE,
+                      state_flags);
 
 // Some themes (Adwaita for instance) draws bold dark line at
 // titlebar bottom. It does not fit well with Firefox tabs so
 // draw with some extent to make the titlebar bottom part invisible.
 #define TITLEBAR_EXTENT 4
 
   // We don't need to draw window decoration for MOZ_GTK_HEADER_BAR_MAXIMIZED,
   // i.e. when main window is maximized.
   if (widgetType == MOZ_GTK_HEADER_BAR) {
-    GtkStyleContext* windowStyle = GetStyleContext(MOZ_GTK_WINDOW);
+    GtkStyleContext* windowStyle = GetStyleContext(MOZ_GTK_WINDOW, state->scale);
     bool solidDecorations =
         gtk_style_context_has_class(windowStyle, "solid-csd");
     GtkStyleContext* decorationStyle =
         GetStyleContext(solidDecorations ? MOZ_GTK_WINDOW_DECORATION_SOLID
                                          : MOZ_GTK_WINDOW_DECORATION,
-                        GTK_TEXT_DIR_LTR, state_flags);
+                        state->scale, GTK_TEXT_DIR_LTR, state_flags);
 
     gtk_render_background(decorationStyle, cr, rect->x, rect->y, rect->width,
                           rect->height + TITLEBAR_EXTENT);
     gtk_render_frame(decorationStyle, cr, rect->x, rect->y, rect->width,
                      rect->height + TITLEBAR_EXTENT);
   }
 
   gtk_render_background(style, cr, rect->x, rect->y, rect->width,
@@ -2432,17 +2475,18 @@ gint moz_gtk_get_widget_border(WidgetNod
   }
   return MOZ_GTK_SUCCESS;
 }
 
 gint moz_gtk_get_tab_border(gint* left, gint* top, gint* right, gint* bottom,
                             GtkTextDirection direction, GtkTabFlags flags,
                             WidgetNodeType widget) {
   GtkStyleContext* style =
-      GetStyleContext(widget, direction, GetStateFlagsFromGtkTabFlags(flags));
+      GetStyleContext(widget, 1, direction,
+      GetStateFlagsFromGtkTabFlags(flags));
 
   *left = *top = *right = *bottom = 0;
   moz_gtk_add_style_padding(style, left, top, right, bottom);
 
   // Gtk >= 3.20 does not use those styles
   if (gtk_check_version(3, 20, 0) != nullptr) {
     int tab_curvature;
 
@@ -2726,17 +2770,17 @@ static void InitScrollbarMetrics(Scrollb
                                  GtkOrientation aOrientation,
                                  GtkStateFlags aStateFlags) {
   WidgetNodeType scrollbar = aOrientation == GTK_ORIENTATION_HORIZONTAL
                                  ? MOZ_GTK_SCROLLBAR_HORIZONTAL
                                  : MOZ_GTK_SCROLLBAR_VERTICAL;
 
   gboolean backward, forward, secondary_backward, secondary_forward;
   GtkStyleContext* style =
-      GetStyleContext(scrollbar, GTK_TEXT_DIR_NONE, aStateFlags);
+      GetStyleContext(scrollbar, 1, GTK_TEXT_DIR_NONE, aStateFlags);
   gtk_style_context_get_style(
       style, "has-backward-stepper", &backward, "has-forward-stepper", &forward,
       "has-secondary-backward-stepper", &secondary_backward,
       "has-secondary-forward-stepper", &secondary_forward, nullptr);
   bool hasButtons =
       backward || forward || secondary_backward || secondary_forward;
 
   if (gtk_get_minor_version() < 20) {
@@ -2806,32 +2850,32 @@ static void InitScrollbarMetrics(Scrollb
    * the Gtk+ css rule looks like:
    *
    *    "scrollbar:hover contents trough slider"
    *
    *  So we need to apply GtkStateFlags to each widgets in style path.
    */
 
   // thumb
-  style = CreateStyleContextWithStates(thumb, GTK_TEXT_DIR_NONE, aStateFlags);
+  style = CreateStyleContextWithStates(thumb, 1, GTK_TEXT_DIR_NONE, aStateFlags);
   aMetrics->size.thumb = GetMinMarginBox(style);
   gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
                                &aMetrics->margin.thumb);
   g_object_unref(style);
 
   // track
-  style = CreateStyleContextWithStates(track, GTK_TEXT_DIR_NONE, aStateFlags);
+  style = CreateStyleContextWithStates(track, 1, GTK_TEXT_DIR_NONE, aStateFlags);
   aMetrics->border.track = GetMarginBorderPadding(style);
   MozGtkSize trackMinSize = GetMinContentBox(style) + aMetrics->border.track;
   MozGtkSize trackSizeForThumb = aMetrics->size.thumb + aMetrics->border.track;
   g_object_unref(style);
 
   // button
   if (hasButtons) {
-    style = CreateStyleContextWithStates(MOZ_GTK_SCROLLBAR_BUTTON,
+    style = CreateStyleContextWithStates(MOZ_GTK_SCROLLBAR_BUTTON, 1,
                                          GTK_TEXT_DIR_NONE, aStateFlags);
     aMetrics->size.button = GetMinMarginBox(style);
     g_object_unref(style);
   } else {
     aMetrics->size.button = {0, 0};
   }
   if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
     aMetrics->size.button.Rotate();
@@ -2857,17 +2901,17 @@ static void InitScrollbarMetrics(Scrollb
       // of center as in gtk_range_compute_slider_position().
       aMetrics->border.track.left += extra / 2;
       aMetrics->border.track.right += extra - extra / 2;
       trackSizeForThumb.width += extra;
     }
   }
 
   style =
-      CreateStyleContextWithStates(contents, GTK_TEXT_DIR_NONE, aStateFlags);
+      CreateStyleContextWithStates(contents, 1, GTK_TEXT_DIR_NONE, aStateFlags);
   GtkBorder contentsBorder = GetMarginBorderPadding(style);
   g_object_unref(style);
 
   aMetrics->size.scrollbar =
       trackSizeForThumb + contentsBorder + aMetrics->border.scrollbar;
 }
 
 const ScrollbarGTKMetrics* GetScrollbarMetrics(GtkOrientation aOrientation) {
@@ -3033,26 +3077,26 @@ gint moz_gtk_widget_paint(WidgetNodeType
     case MOZ_GTK_SCALE_THUMB_VERTICAL:
       return moz_gtk_scale_thumb_paint(cr, rect, state, (GtkOrientation)flags,
                                        direction);
       break;
     case MOZ_GTK_INNER_SPIN_BUTTON:
       return moz_gtk_inner_spin_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_SPINBUTTON:
-      return moz_gtk_spin_paint(cr, rect, direction);
+      return moz_gtk_spin_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_SPINBUTTON_UP:
     case MOZ_GTK_SPINBUTTON_DOWN:
       return moz_gtk_spin_updown_paint(
           cr, rect, (widget == MOZ_GTK_SPINBUTTON_DOWN), state, direction);
       break;
     case MOZ_GTK_SPINBUTTON_ENTRY: {
       GtkStyleContext* style =
-          GetStyleContext(MOZ_GTK_SPINBUTTON_ENTRY, direction,
+          GetStyleContext(MOZ_GTK_SPINBUTTON_ENTRY, state->scale, direction,
                           GetStateFlagsFromGtkWidgetState(state));
       gint ret = moz_gtk_entry_paint(cr, rect, state, style, widget);
       return ret;
     } break;
     case MOZ_GTK_GRIPPER:
       return moz_gtk_gripper_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_TREEVIEW:
@@ -3067,17 +3111,18 @@ gint moz_gtk_widget_paint(WidgetNodeType
       break;
     case MOZ_GTK_TREEVIEW_EXPANDER:
       return moz_gtk_treeview_expander_paint(
           cr, rect, state, (GtkExpanderStyle)flags, direction);
       break;
     case MOZ_GTK_ENTRY:
     case MOZ_GTK_DROPDOWN_ENTRY: {
       GtkStyleContext* style = GetStyleContext(
-          widget, direction, GetStateFlagsFromGtkWidgetState(state));
+          widget, state->scale, direction,
+          GetStateFlagsFromGtkWidgetState(state));
       gint ret = moz_gtk_entry_paint(cr, rect, state, style, widget);
       return ret;
     }
     case MOZ_GTK_TEXT_VIEW:
       return moz_gtk_text_view_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_DROPDOWN:
       return moz_gtk_combo_box_paint(cr, rect, state, direction);
@@ -3091,58 +3136,58 @@ gint moz_gtk_widget_paint(WidgetNodeType
       return moz_gtk_container_paint(cr, rect, state, widget, direction);
       break;
     case MOZ_GTK_CHECKBUTTON_LABEL:
     case MOZ_GTK_RADIOBUTTON_LABEL:
       return moz_gtk_toggle_label_paint(
           cr, rect, state, (widget == MOZ_GTK_RADIOBUTTON_LABEL), direction);
       break;
     case MOZ_GTK_TOOLBAR:
-      return moz_gtk_toolbar_paint(cr, rect, direction);
+      return moz_gtk_toolbar_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_TOOLBAR_SEPARATOR:
-      return moz_gtk_toolbar_separator_paint(cr, rect, direction);
+      return moz_gtk_toolbar_separator_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_TOOLTIP:
-      return moz_gtk_tooltip_paint(cr, rect, direction);
+      return moz_gtk_tooltip_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_FRAME:
-      return moz_gtk_frame_paint(cr, rect, direction);
+      return moz_gtk_frame_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_RESIZER:
       return moz_gtk_resizer_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_PROGRESSBAR:
-      return moz_gtk_progressbar_paint(cr, rect, direction);
+      return moz_gtk_progressbar_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_PROGRESS_CHUNK:
     case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE:
     case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE:
-      return moz_gtk_progress_chunk_paint(cr, rect, direction, widget);
+      return moz_gtk_progress_chunk_paint(cr, rect, state, direction, widget);
       break;
     case MOZ_GTK_TAB_TOP:
     case MOZ_GTK_TAB_BOTTOM:
       return moz_gtk_tab_paint(cr, rect, state, (GtkTabFlags)flags, direction,
                                widget);
       break;
     case MOZ_GTK_TABPANELS:
-      return moz_gtk_tabpanels_paint(cr, rect, direction);
+      return moz_gtk_tabpanels_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_TAB_SCROLLARROW:
       return moz_gtk_tab_scroll_arrow_paint(cr, rect, state,
                                             (GtkArrowType)flags, direction);
       break;
     case MOZ_GTK_MENUBAR:
-      return moz_gtk_menu_bar_paint(cr, rect, direction);
+      return moz_gtk_menu_bar_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_MENUPOPUP:
-      return moz_gtk_menu_popup_paint(cr, rect, direction);
+      return moz_gtk_menu_popup_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_MENUSEPARATOR:
-      return moz_gtk_menu_separator_paint(cr, rect, direction);
+      return moz_gtk_menu_separator_paint(cr, rect, state, direction);
       break;
     case MOZ_GTK_MENUBARITEM:
     case MOZ_GTK_MENUITEM:
       return moz_gtk_menu_item_paint(widget, cr, rect, state, direction);
       break;
     case MOZ_GTK_MENUARROW:
       return moz_gtk_menu_arrow_paint(cr, rect, state, direction);
       break;