[firefox] Gtk3 - fixed tabs rendering

Martin Stransky stransky at fedoraproject.org
Mon Jan 19 13:46:13 UTC 2015


commit ff3c231d81fcbd2185e54848e6d7bfbff4d59d82
Author: Martin Stransky <stransky at redhat.com>
Date:   Mon Jan 19 14:46:35 2015 +0100

    Gtk3 - fixed tabs rendering

 firefox.spec                     |    7 +-
 mozilla-1073117-no-gap-tab.patch |  463 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 469 insertions(+), 1 deletions(-)
---
diff --git a/firefox.spec b/firefox.spec
index fdc498f..3354e36 100644
--- a/firefox.spec
+++ b/firefox.spec
@@ -107,7 +107,7 @@
 Summary:        Mozilla Firefox Web browser
 Name:           firefox
 Version:        35.0
-Release:        3%{?pre_tag}%{?dist}
+Release:        4%{?pre_tag}%{?dist}
 URL:            http://www.mozilla.org/projects/firefox/
 License:        MPLv1.1 or GPLv2+ or LGPLv2+
 Group:          Applications/Internet
@@ -155,6 +155,7 @@ Patch408:        mozilla-1110211.patch
 Patch409:        mozilla-1073117-entry-button-size.patch
 Patch410:        mozilla-1073117-button-focus.patch
 Patch411:        mozilla-1073117-focus-sizes.patch
+Patch412:        mozilla-1073117-no-gap-tab.patch
 
 %if %{official_branding}
 # Required by Mozilla Corporation
@@ -312,6 +313,7 @@ cd %{tarballdir}
 %patch409 -p1 -b .1073117-entry-button-size
 %patch410 -p1 -b .1073117-button-focus
 %patch411 -p1 -b .1073117-focus-sizes
+%patch412 -p1 -b .1073117-no-gap-tab
 %endif
 
 %if %{official_branding}
@@ -765,6 +767,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 #---------------------------------------------------------------------
 
 %changelog
+* Mon Jan 19 2015 Martin Stransky <stransky at redhat.com> - 35.0-4
+- Gtk3 - fixed tabs rendering
+
 * Wed Jan 14 2015 Martin Stransky <stransky at redhat.com> - 35.0-3
 - Gtk3 - replaced obsoleted focus properties
 - Make start.fedoraproject.org the homepage
diff --git a/mozilla-1073117-no-gap-tab.patch b/mozilla-1073117-no-gap-tab.patch
new file mode 100644
index 0000000..2ca16c7
--- /dev/null
+++ b/mozilla-1073117-no-gap-tab.patch
@@ -0,0 +1,463 @@
+diff --git a/widget/gtk/gtk3drawing.c b/widget/gtk/gtk3drawing.c
+--- a/widget/gtk/gtk3drawing.c
++++ b/widget/gtk/gtk3drawing.c
+@@ -2098,18 +2098,23 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
+     return MOZ_GTK_SUCCESS;
+ }
+ 
+ gint
+ moz_gtk_get_tab_thickness(void)
+ {
+     GtkBorder border;
+     GtkStyleContext * style;
++    gboolean has_tab_gap;
+ 
+     ensure_tab_widget();
++    gtk_widget_style_get(gTabWidget, "has-tab-gap", &has_tab_gap, NULL);
++    if (!has_tab_gap)
++      return 0; /* don't use ythickness for tabs without a gap */
++
+     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;
+@@ -2140,172 +2145,196 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
+      * When it is selected, we overwrite the adjacent border of the tabpanel
+      * touching the tab with a pierced border (called "the gap") to make the
+      * tab appear physically attached to the tabpanel; see details below. */
+ 
+     GtkStyleContext* style;
+     GdkRectangle tabRect;
+     GdkRectangle focusRect;
+     GdkRectangle backRect;
++    gboolean has_tab_gap;
+     int initial_gap = 0;
+ 
+     ensure_tab_widget();
+     gtk_widget_set_direction(gTabWidget, direction);
+ 
+     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;
++    gtk_widget_style_get(gTabWidget, "has-tab-gap", &has_tab_gap, NULL);
++    if (has_tab_gap) {
++        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 );
++
++        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 (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 (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);
++
++              gtk_render_focus(style, cr,
++                              focusRect.x, focusRect.y, focusRect.width, focusRect.height);
++            }
++        }
+     } 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;
++        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);
++
++        if (state->focused) {
++          /* Paint the focus ring */
++          GtkBorder padding;
++
++          GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
++
++          focusRect = *rect;
++          gtk_style_context_get_padding(style, state_flags, &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);
+         }
+-
+-        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 (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);
+-
+-      gtk_render_focus(style, cr,
+-                      focusRect.x, focusRect.y, focusRect.width, focusRect.height);
+     }
+ 
+     gtk_style_context_restore(style);
+ 
+     return MOZ_GTK_SUCCESS;
+ }
+ 
+ /* tab area*/
+@@ -2963,48 +2992,53 @@ moz_gtk_get_widget_border(GtkThemeWidget
+ }
+ 
+ gint
+ moz_gtk_get_tab_border(gint* left, gint* top, gint* right, gint* bottom, 
+                        GtkTextDirection direction, GtkTabFlags flags)
+ {
+     GtkStyleContext* style;    
+     int tab_curvature;
++    gboolean has_tab_gap;
+ 
+     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;
+-      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;
++    gtk_widget_style_get(gTabWidget, "has-tab-gap", &has_tab_gap, NULL);
++    if (has_tab_gap) {
++      moz_gtk_add_style_border(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;
++        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;
++      }
+     }
+ 
+     gtk_style_context_restore(style);
+ 
+     return MOZ_GTK_SUCCESS;
+ }
+ 
+ gint
+diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp
+--- a/widget/gtk/nsNativeThemeGTK.cpp
++++ b/widget/gtk/nsNativeThemeGTK.cpp
+@@ -756,16 +756,18 @@ nsNativeThemeGTK::GetExtraSizeForWidget(
+       return true;
+     }
+   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 {


More information about the scm-commits mailing list