Bug 1073117 - Add support for has_tab_gap notebook style. r=karlt
authorMartin Stransky <stransky@redhat.com>
Thu, 30 Apr 2015 01:31:00 -0400
changeset 273621 1bc82fa210381fd026ddd9dbe40d214929fd01d8
parent 273620 ef4588e3937d36234a641ed42384238c784df23f
child 273622 8bc8f9c19385d97167982b31f08cd7fa73d3df3d
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1073117
milestone40.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 1073117 - Add support for has_tab_gap notebook style. r=karlt
widget/gtk/gtk3drawing.c
widget/gtk/nsNativeThemeGTK.cpp
--- a/widget/gtk/gtk3drawing.c
+++ b/widget/gtk/gtk3drawing.c
@@ -60,16 +60,17 @@ static GtkWidget* gToolbarSeparatorWidge
 static GtkWidget* gMenuSeparatorWidget;
 static GtkWidget* gHPanedWidget;
 static GtkWidget* gVPanedWidget;
 static GtkWidget* gScrolledWindowWidget;
 
 static style_prop_t style_prop_func;
 static gboolean have_arrow_scaling;
 static gboolean checkbox_check_state;
+static gboolean notebook_has_tab_gap;
 static gboolean is_initialized;
 
 #define ARROW_UP      0
 #define ARROW_DOWN    G_PI
 #define ARROW_RIGHT   G_PI_2
 #define ARROW_LEFT    (G_PI+G_PI_2)
 
 #if !GTK_CHECK_VERSION(3,14,0)
@@ -720,16 +721,24 @@ moz_gtk_init()
     have_arrow_scaling = (gtk_major_version > 2 ||
                           (gtk_major_version == 2 && gtk_minor_version >= 12));
     if (gtk_major_version > 3 ||
        (gtk_major_version == 3 && gtk_minor_version >= 14))
         checkbox_check_state = GTK_STATE_FLAG_CHECKED;
     else
         checkbox_check_state = GTK_STATE_FLAG_ACTIVE;
 
+    if(!gtk_check_version(3, 12, 0)) {
+        ensure_tab_widget();
+        gtk_widget_style_get(gTabWidget, "has-tab-gap", &notebook_has_tab_gap, NULL);
+    }
+    else {
+        notebook_has_tab_gap = TRUE;
+    }
+
     /* Add style property to GtkEntry.
      * Adding the style property to the normal GtkEntry class means that it
      * will work without issues inside GtkComboBox and for Spinbuttons. */
     entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
 
     return MOZ_GTK_SUCCESS;
 }
 
@@ -2007,16 +2016,19 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
 
 gint
 moz_gtk_get_tab_thickness(void)
 {
     GtkBorder border;
     GtkStyleContext * style;
 
     ensure_tab_widget();
+    if (!notebook_has_tab_gap)
+      return 0; /* tabs do not overdraw the tabpanel border with "no gap" style */
+
     style = gtk_widget_get_style_context(gTabWidget);
     gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK);
     gtk_style_context_get_border(style, 0, &border);
 
     if (border.top < 2)
         return 2; /* some themes don't set ythickness correctly */
 
     return border.top;
@@ -2052,170 +2064,182 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
     GdkRectangle tabRect;
     GdkRectangle focusRect;
     GdkRectangle backRect;
     int initial_gap = 0;
 
     ensure_tab_widget();
     gtk_widget_set_direction(gTabWidget, direction);
 
-    style = gtk_widget_get_style_context(gTabWidget);    
+    style = gtk_widget_get_style_context(gTabWidget);
     gtk_style_context_save(style);
     moz_gtk_tab_prepare_style_context(style, flags);
 
     tabRect = *rect;
 
     if (flags & MOZ_GTK_TAB_FIRST) {
         gtk_widget_style_get (gTabWidget, "initial-gap", &initial_gap, NULL);
         tabRect.width -= initial_gap;
 
         if (direction != GTK_TEXT_DIR_RTL) {
             tabRect.x += initial_gap;
         }
     }
 
     focusRect = backRect = tabRect;
 
-    if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
-        /* Only draw the tab */
-        gtk_render_extension(style, cr,
-                             tabRect.x, tabRect.y, tabRect.width, tabRect.height,
-                            (flags & MOZ_GTK_TAB_BOTTOM) ?
-                                GTK_POS_TOP : GTK_POS_BOTTOM );
-    } else {
-        /* Draw the tab and the gap
-         * We want the gap to be positioned exactly on the tabpanel top
-         * border; since tabbox.css may set a negative margin so that the tab
-         * frame rect already overlaps the tabpanel frame rect, we need to take
-         * that into account when drawing. To that effect, nsNativeThemeGTK
-         * passes us this negative margin (bmargin in the graphic below) in the
-         * lowest bits of |flags|.  We use it to set gap_voffset, the distance
-         * between the top of the gap and the bottom of the tab (resp. the
-         * bottom of the gap and the top of the tab when we draw a bottom tab),
-         * while ensuring that the gap always touches the border of the tab,
-         * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
-         * with big negative or positive margins.
-         * Here is a graphical explanation in the case of top tabs:
-         *             ___________________________
-         *            /                           \
-         *           |            T A B            |
-         * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
-         *           :    ^       bmargin          :  ^
-         *           :    | (-negative margin,     :  |
-         *  bottom   :    v  passed in flags)      :  |       gap_height
-         *    of  -> :.............................:  |    (the size of the
-         * the tab   .       part of the gap       .  |  tabpanel top border)
-         *           .      outside of the tab     .  v
-         * ----------------------------------------------
-         *
-         * To draw the gap, we use gtk_paint_box_gap(), see comment in
-         * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
-         * which should suffice to ensure that the only visible border is the
-         * pierced one.  If the tab is in the middle, we make the box_gap begin
-         * a bit to the left of the tab and end a bit to the right, adjusting
-         * the gap position so it still is under the tab, because we want the
-         * rendering of a gap in the middle of a tabpanel.  This is the role of
-         * the gints gap_{l,r}_offset. On the contrary, if the tab is the
-         * first, we align the start border of the box_gap with the start
-         * border of the tab (left if LTR, right if RTL), by setting the
-         * appropriate offset to 0.*/
-        gint gap_loffset, gap_roffset, gap_voffset, gap_height;
-
-        /* Get height needed by the gap */
-        gap_height = moz_gtk_get_tab_thickness();
-
-        /* Extract gap_voffset from the first bits of flags */
-        gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
-        if (gap_voffset > gap_height)
-            gap_voffset = gap_height;
-
-        /* Set gap_{l,r}_offset to appropriate values */
-        gap_loffset = gap_roffset = 20; /* should be enough */
-        if (flags & MOZ_GTK_TAB_FIRST) {
-            if (direction == GTK_TEXT_DIR_RTL)
-                gap_roffset = initial_gap;
-            else
-                gap_loffset = initial_gap;
+    if (notebook_has_tab_gap) {
+        if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
+            /* Only draw the tab */
+            gtk_render_extension(style, cr,
+                                 tabRect.x, tabRect.y, tabRect.width, tabRect.height,
+                                (flags & MOZ_GTK_TAB_BOTTOM) ?
+                                    GTK_POS_TOP : GTK_POS_BOTTOM );
+        } else {
+            /* Draw the tab and the gap
+             * We want the gap to be positioned exactly on the tabpanel top
+             * border; since tabbox.css may set a negative margin so that the tab
+             * frame rect already overlaps the tabpanel frame rect, we need to take
+             * that into account when drawing. To that effect, nsNativeThemeGTK
+             * passes us this negative margin (bmargin in the graphic below) in the
+             * lowest bits of |flags|.  We use it to set gap_voffset, the distance
+             * between the top of the gap and the bottom of the tab (resp. the
+             * bottom of the gap and the top of the tab when we draw a bottom tab),
+             * while ensuring that the gap always touches the border of the tab,
+             * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
+             * with big negative or positive margins.
+             * Here is a graphical explanation in the case of top tabs:
+             *             ___________________________
+             *            /                           \
+             *           |            T A B            |
+             * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
+             *           :    ^       bmargin          :  ^
+             *           :    | (-negative margin,     :  |
+             *  bottom   :    v  passed in flags)      :  |       gap_height
+             *    of  -> :.............................:  |    (the size of the
+             * the tab   .       part of the gap       .  |  tabpanel top border)
+             *           .      outside of the tab     .  v
+             * ----------------------------------------------
+             *
+             * To draw the gap, we use gtk_paint_box_gap(), see comment in
+             * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
+             * which should suffice to ensure that the only visible border is the
+             * pierced one.  If the tab is in the middle, we make the box_gap begin
+             * a bit to the left of the tab and end a bit to the right, adjusting
+             * the gap position so it still is under the tab, because we want the
+             * rendering of a gap in the middle of a tabpanel.  This is the role of
+             * the gints gap_{l,r}_offset. On the contrary, if the tab is the
+             * first, we align the start border of the box_gap with the start
+             * border of the tab (left if LTR, right if RTL), by setting the
+             * appropriate offset to 0.*/
+            gint gap_loffset, gap_roffset, gap_voffset, gap_height;
+
+            /* Get height needed by the gap */
+            gap_height = moz_gtk_get_tab_thickness();
+
+            /* Extract gap_voffset from the first bits of flags */
+            gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
+            if (gap_voffset > gap_height)
+                gap_voffset = gap_height;
+
+            /* Set gap_{l,r}_offset to appropriate values */
+            gap_loffset = gap_roffset = 20; /* should be enough */
+            if (flags & MOZ_GTK_TAB_FIRST) {
+                if (direction == GTK_TEXT_DIR_RTL)
+                    gap_roffset = initial_gap;
+                else
+                    gap_loffset = initial_gap;
+            }
+
+            if (flags & MOZ_GTK_TAB_BOTTOM) {
+                /* 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, GTK_POS_TOP);
+
+                gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
+
+                backRect.y += (gap_voffset - gap_height);
+                backRect.height = gap_height;
+
+                /* Draw the gap; erase with background color before painting in
+                 * case theme does not */
+                gtk_render_background(style, cr, backRect.x, backRect.y,
+                                     backRect.width, backRect.height);
+                cairo_save(cr);
+                cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
+                cairo_clip(cr);
+
+                gtk_render_frame_gap(style, cr,
+                                     tabRect.x - gap_loffset,
+                                     tabRect.y + gap_voffset - 3 * gap_height,
+                                     tabRect.width + gap_loffset + gap_roffset,
+                                     3 * gap_height, GTK_POS_BOTTOM,
+                                     gap_loffset, gap_loffset + tabRect.width);
+                cairo_restore(cr);
+            } else {
+                /* Draw the tab on top */
+                focusRect.height -= gap_voffset;
+                gtk_render_extension(style, cr,
+                                     tabRect.x, tabRect.y, tabRect.width,
+                                     tabRect.height - gap_voffset, GTK_POS_BOTTOM);
+
+                gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
+
+                backRect.y += (tabRect.height - gap_voffset);
+                backRect.height = gap_height;
+
+                /* Draw the gap; erase with background color before painting in
+                 * case theme does not */
+                gtk_render_background(style, cr, backRect.x, backRect.y,
+                                      backRect.width, backRect.height);
+
+                cairo_save(cr);
+                cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
+                cairo_clip(cr);
+
+                gtk_render_frame_gap(style, cr,
+                                     tabRect.x - gap_loffset,
+                                     tabRect.y + tabRect.height - gap_voffset,
+                                     tabRect.width + gap_loffset + gap_roffset,
+                                     3 * gap_height, GTK_POS_TOP,
+                                     gap_loffset, gap_loffset + tabRect.width);
+                cairo_restore(cr);
+            }
         }
-
-        if (flags & MOZ_GTK_TAB_BOTTOM) {
-            /* 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, GTK_POS_TOP);
-
-            gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
-
-            backRect.y += (gap_voffset - gap_height);
-            backRect.height = gap_height;
-
-            /* Draw the gap; erase with background color before painting in
-             * case theme does not */
-            gtk_render_background(style, cr, backRect.x, backRect.y,
-                                 backRect.width, backRect.height);
-            cairo_save(cr);
-            cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
-            cairo_clip(cr);
-
-            gtk_render_frame_gap(style, cr,
-                                 tabRect.x - gap_loffset,
-                                 tabRect.y + gap_voffset - 3 * gap_height,
-                                 tabRect.width + gap_loffset + gap_roffset,
-                                 3 * gap_height, GTK_POS_BOTTOM,
-                                 gap_loffset, gap_loffset + tabRect.width);
-            cairo_restore(cr);
-        } else {
-            /* Draw the tab on top */
-            focusRect.height -= gap_voffset;
-            gtk_render_extension(style, cr,
-                                 tabRect.x, tabRect.y, tabRect.width,
-                                 tabRect.height - gap_voffset, GTK_POS_BOTTOM);
-
-            gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
-
-            backRect.y += (tabRect.height - gap_voffset);
-            backRect.height = gap_height;
-
-            /* Draw the gap; erase with background color before painting in
-             * case theme does not */
-            gtk_render_background(style, cr, backRect.x, backRect.y,
-                                  backRect.width, backRect.height);
-
-            cairo_save(cr);
-            cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
-            cairo_clip(cr);
-
-            gtk_render_frame_gap(style, cr,
-                                 tabRect.x - gap_loffset,
-                                 tabRect.y + tabRect.height - gap_voffset,
-                                 tabRect.width + gap_loffset + gap_roffset,
-                                 3 * gap_height, GTK_POS_TOP,
-                                 gap_loffset, gap_loffset + tabRect.width);
-            cairo_restore(cr);
-        }
+    } else {
+        gtk_render_background(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
+        gtk_render_frame(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
     }
 
+    gtk_style_context_restore(style);
+
     if (state->focused) {
       /* Paint the focus ring */
-      GtkBorder border;
-      gtk_style_context_get_border(style, GetStateFlagsFromGtkWidgetState(state), &border);
-
-      focusRect.x += border.left;
-      focusRect.width -= (border.left + border.right);
-      focusRect.y += border.top;
-      focusRect.height -= (border.top + border.bottom);
+      GtkBorder padding;
+
+      gtk_style_context_save(style);
+      moz_gtk_tab_prepare_style_context(style, flags);
+
+      gtk_style_context_get_padding(style, GetStateFlagsFromGtkWidgetState(state), &padding);
+
+      focusRect.x += padding.left;
+      focusRect.width -= (padding.left + padding.right);
+      focusRect.y += padding.top;
+      focusRect.height -= (padding.top + padding.bottom);
 
       gtk_render_focus(style, cr,
                       focusRect.x, focusRect.y, focusRect.width, focusRect.height);
+
+      gtk_style_context_restore(style);
     }
 
-    gtk_style_context_restore(style);
 
     return MOZ_GTK_SUCCESS;
 }
 
 /* tab area*/
 static gint
 moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
                         GtkTextDirection direction)
@@ -2826,41 +2850,30 @@ moz_gtk_get_tab_border(gint* left, gint*
     int tab_curvature;
 
     ensure_tab_widget();
 
     style = gtk_widget_get_style_context(gTabWidget);
     gtk_style_context_save(style);
     moz_gtk_tab_prepare_style_context(style, flags);
 
-    // TODO add_style_border() should be replaced
-    // with focus-line-width and focus-padding
-    // see Bug 877605
     *left = *top = *right = *bottom = 0;
-    moz_gtk_add_style_border(style, left, top, right, bottom);
     moz_gtk_add_style_padding(style, left, top, right, bottom);
 
     gtk_widget_style_get (gTabWidget, "tab-curvature", &tab_curvature, NULL);
     *left += tab_curvature;
     *right += tab_curvature;
 
     if (flags & MOZ_GTK_TAB_FIRST) {
       int initial_gap;
       gtk_widget_style_get (gTabWidget, "initial-gap", &initial_gap, NULL);
       if (direction == GTK_TEXT_DIR_RTL)
-      	*right += initial_gap;
+        *right += initial_gap;
       else
-      	*left += initial_gap;
-    }
-
-    // Top tabs have no bottom border, bottom tabs have no top border
-    if (flags & MOZ_GTK_TAB_BOTTOM) {
-      *top = 0;
-    } else {
-      *bottom = 0;
+        *left += initial_gap;
     }
 
     gtk_style_context_restore(style);
 
     return MOZ_GTK_SUCCESS;
 }
 
 gint
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -760,16 +760,18 @@ nsNativeThemeGTK::GetExtraSizeForWidget(
       break;
     }
   case NS_THEME_TAB :
     {
       if (!IsSelectedTab(aFrame))
         return false;
 
       gint gap_height = moz_gtk_get_tab_thickness();
+      if (!gap_height)
+        return false;
 
       int32_t extra = gap_height - GetTabMarginPixels(aFrame);
       if (extra <= 0)
         return false;
 
       if (IsBottomTab(aFrame)) {
         aExtra->top = extra;
       } else {