Bug 1355143 - Provide ScrollbarGTKMetrics for active (mouse over) scrollbars, r?jhorak draft
authorMartin Stransky <stransky@redhat.com>
Wed, 18 Apr 2018 11:05:46 +0200
changeset 784987 478e40f73cee64d4e39971b09240b1881697a07d
parent 784986 f6b3d279049b97d184f8a379f8b5afbb17b0a4ab
child 784988 86e94e01b0fa86fbce50e079066fbedccc45b239
push id107085
push userstransky@redhat.com
push dateThu, 19 Apr 2018 11:45:09 +0000
reviewersjhorak
bugs1355143
milestone61.0a1
Bug 1355143 - Provide ScrollbarGTKMetrics for active (mouse over) scrollbars, r?jhorak MozReview-Commit-ID: 95d1jeQ8mXd
widget/gtk/gtk3drawing.cpp
widget/gtk/gtkdrawing.h
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -19,16 +19,17 @@
 
 #include <math.h>
 #include <dlfcn.h>
 
 static gboolean checkbox_check_state;
 static gboolean notebook_has_tab_gap;
 
 static ScrollbarGTKMetrics sScrollbarMetrics[2];
+static ScrollbarGTKMetrics sScrollbarMetricsActive[2];
 static ToggleGTKMetrics sCheckboxMetrics;
 static ToggleGTKMetrics sRadioMetrics;
 static ToolbarGTKMetrics sToolbarMetrics;
 
 #define ARROW_UP      0
 #define ARROW_DOWN    G_PI
 #define ARROW_RIGHT   G_PI_2
 #define ARROW_LEFT    (G_PI+G_PI_2)
@@ -177,16 +178,18 @@ moz_gtk_refresh()
                                     "has-tab-gap", &notebook_has_tab_gap, NULL);
     }
     else {
         notebook_has_tab_gap = true;
     }
 
     sScrollbarMetrics[GTK_ORIENTATION_HORIZONTAL].initialized = false;
     sScrollbarMetrics[GTK_ORIENTATION_VERTICAL].initialized = false;
+    sScrollbarMetricsActive[GTK_ORIENTATION_HORIZONTAL].initialized = false;
+    sScrollbarMetricsActive[GTK_ORIENTATION_VERTICAL].initialized = false;
     sCheckboxMetrics.initialized = false;
     sRadioMetrics.initialized = false;
     sToolbarMetrics.initialized = false;
 
     /* This will destroy all of our widgets */
     ResetWidgetCache();
 }
 
@@ -735,20 +738,19 @@ GetMinContentBox(GtkStyleContext* style)
     return {width, height};
 }
 
 /**
  * Get minimum widget size as sum of margin, padding, border and
  * min-width/min-height.
  */
 static void
-moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width,
+moz_gtk_get_widget_min_size(GtkStyleContext* style, int* width,
                             int* height)
 {
-  GtkStyleContext* style = GetStyleContext(aGtkWidgetType);
   GtkStateFlags state_flags = gtk_style_context_get_state(style);
   gtk_style_context_get(style, state_flags,
                         "min-height", height,
                         "min-width", width,
                         nullptr);
 
   GtkBorder border, padding, margin;
   gtk_style_context_get_border(style, state_flags, &border);
@@ -757,20 +759,20 @@ moz_gtk_get_widget_min_size(WidgetNodeTy
 
   *width += border.left + border.right + margin.left + margin.right +
             padding.left + padding.right;
   *height += border.top + border.bottom + margin.top + margin.bottom +
              padding.top + padding.bottom;
 }
 
 static MozGtkSize
-GetMinMarginBox(WidgetNodeType aNodeType)
+GetMinMarginBox(GtkStyleContext* style)
 {
     gint width, height;
-    moz_gtk_get_widget_min_size(aNodeType, &width, &height);
+    moz_gtk_get_widget_min_size(style, &width, &height);
     return {width, height};
 }
 
 static void
 Inset(GdkRectangle* rect, const GtkBorder& aBorder)
 {
     MOZ_ASSERT(rect);
     rect->x += aBorder.left;
@@ -942,17 +944,17 @@ moz_gtk_scrollbar_trough_paint(WidgetNod
 {
     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(thumb);
+        MozGtkSize thumbSize = GetMinMarginBox(GetStyleContext(thumb));
         style = GetStyleContext(widget, direction);
         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) {
@@ -2760,17 +2762,18 @@ moz_gtk_get_scale_metrics(GtkOrientation
       } else {
           *scale_width = thumb_height + trough_border * 2;
           *scale_height = thumb_length + trough_border * 2;
       }
   } else {
       WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
                                MOZ_GTK_SCALE_TROUGH_HORIZONTAL :
                                MOZ_GTK_SCALE_TROUGH_VERTICAL;
-      moz_gtk_get_widget_min_size(widget, scale_width, scale_height);
+      moz_gtk_get_widget_min_size(GetStyleContext(widget),
+                                  scale_width, scale_height);
   }
 }
 
 gint
 moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
 {
 
   if (gtk_check_version(3, 20, 0) != nullptr) {
@@ -2879,29 +2882,32 @@ GetToggleMetrics(bool isRadio)
                              nullptr);
         metrics->minSizeWithBorder.width =
             metrics->minSizeWithBorder.height = indicator_size;
     }
     return metrics;
 }
 
 const ScrollbarGTKMetrics*
-GetScrollbarMetrics(GtkOrientation aOrientation)
+GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive)
 {
-    auto metrics = &sScrollbarMetrics[aOrientation];
+    auto metrics = aActive ? &sScrollbarMetricsActive[aOrientation] :
+                             &sScrollbarMetrics[aOrientation];
     if (metrics->initialized)
         return metrics;
 
     metrics->initialized = true;
 
     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);
+    GtkStyleContext* style = GetStyleContext(scrollbar, GTK_TEXT_DIR_NONE,
+                             aActive ? GTK_STATE_FLAG_PRELIGHT :
+                                       GTK_STATE_FLAG_NORMAL);
     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 =
@@ -2958,26 +2964,58 @@ GetScrollbarMetrics(GtkOrientation aOrie
         contents = MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL;
         track = MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL;
         thumb = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
     } else {
         contents = MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL;
         track = MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
         thumb = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
     }
+
+    /* GetStyleContext() sets GtkStateFlags to the latest widget name
+     * in css selector string. When we call:
+     *
+     *     GetStyleContext(thumb, GTK_STATE_FLAG_PRELIGHT)
+     *
+     * we get:
+     *
+     *    "scrollbar contents trough slider:hover"
+     *
+     * Some themes (Ubuntu Ambiance) styles trough/thumb by scrollbar,
+     * the Gtk+ css rule looks like:
+     *
+     *    "scrollbar:hover contents trough slider"
+     *
+     *  So we need to apply GtkStateFlags to each widgets in style path.
+     */
+
     // thumb
-    metrics->size.thumb = GetMinMarginBox(thumb);
+    style = CreateStyleContextWithStates(thumb, GTK_TEXT_DIR_NONE,
+                                         aActive ? GTK_STATE_FLAG_PRELIGHT :
+                                                   GTK_STATE_FLAG_NORMAL);
+    metrics->size.thumb = GetMinMarginBox(style);
+    g_object_unref(style);
+
     // track
-    style = GetStyleContext(track);
+    style = CreateStyleContextWithStates(track, GTK_TEXT_DIR_NONE,
+                                         aActive ? GTK_STATE_FLAG_PRELIGHT :
+                                                   GTK_STATE_FLAG_NORMAL);
     metrics->border.track = GetMarginBorderPadding(style);
     MozGtkSize trackMinSize = GetMinContentBox(style) + metrics->border.track;
     MozGtkSize trackSizeForThumb = metrics->size.thumb + metrics->border.track;
+    g_object_unref(style);
+
     // button
     if (hasButtons) {
-        metrics->size.button = GetMinMarginBox(MOZ_GTK_SCROLLBAR_BUTTON);
+        style = CreateStyleContextWithStates(MOZ_GTK_SCROLLBAR_BUTTON,
+                                             GTK_TEXT_DIR_NONE,
+                                             aActive ? GTK_STATE_FLAG_PRELIGHT :
+                                                       GTK_STATE_FLAG_NORMAL);
+        metrics->size.button = GetMinMarginBox(style);
+        g_object_unref(style);
     } else {
         metrics->size.button = {0, 0};
     }
     if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
         metrics->size.button.Rotate();
         // If the track is wider than necessary for the thumb, including when
         // the buttons will cause Gecko to expand the track to fill
         // available breadth, then add to the track border to prevent Gecko
@@ -3001,18 +3039,21 @@ GetScrollbarMetrics(GtkOrientation aOrie
             // If extra is odd, then the thumb is 0.5 pixels to the left
             // of center as in gtk_range_compute_slider_position().
             metrics->border.track.left += extra / 2;
             metrics->border.track.right += extra - extra / 2;
             trackSizeForThumb.width += extra;
         }
     }
 
-    style = GetStyleContext(contents);
+    style = CreateStyleContextWithStates(contents, GTK_TEXT_DIR_NONE,
+                                            aActive ? GTK_STATE_FLAG_PRELIGHT :
+                                                      GTK_STATE_FLAG_NORMAL);
     GtkBorder contentsBorder = GetMarginBorderPadding(style);
+    g_object_unref(style);
 
     metrics->size.scrollbar =
         trackSizeForThumb + contentsBorder + metrics->border.scrollbar;
 
     return metrics;
 }
 
 /* cairo_t *cr argument has to be a system-cairo. */
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -48,16 +48,21 @@ struct MozGtkSize {
     height += aBorder.top + aBorder.bottom;
     return *this;
   }
   MozGtkSize operator+(const GtkBorder& aBorder) const
   {
     MozGtkSize result = *this;
     return result += aBorder;
   }
+  bool operator<(const MozGtkSize &aOther) const
+  {
+    return (width < aOther.width && height <= aOther.height) ||
+           (width <= aOther.width && height < aOther.height);
+  }
   void Include(MozGtkSize aOther)
   {
     width = std::max(width, aOther.width);
     height = std::max(height, aOther.height);
   }
   void Rotate()
   {
     gint tmp = width;
@@ -486,19 +491,22 @@ moz_gtk_get_scale_metrics(GtkOrientation
  *
  * returns:    MOZ_GTK_SUCCESS if there was no error, an error code otherwise
  */
 gint
 moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height);
 
 /**
  * Get the metrics in GTK pixels for a scrollbar.
+ * aOrientation:     [IN] the scrollbar orientation
+ * aActive:          [IN] Metricts for scrollbar with mouse pointer over it.
+ *
  */
 const ScrollbarGTKMetrics*
-GetScrollbarMetrics(GtkOrientation aOrientation);
+GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive = false);
 
 /**
  * Get the desired size of a dropdown arrow button
  * width:   [OUT] the desired width
  * height:  [OUT] the desired height
  *
  * returns:    MOZ_GTK_SUCCESS if there was no error, an error code otherwise
  */