From ff3c231d81fcbd2185e54848e6d7bfbff4d59d82 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Mon, 19 Jan 2015 14:46:35 +0100 Subject: [PATCH] Gtk3 - fixed tabs rendering --- firefox.spec | 7 +- mozilla-1073117-no-gap-tab.patch | 463 +++++++++++++++++++++++++++++++ 2 files changed, 469 insertions(+), 1 deletion(-) create mode 100644 mozilla-1073117-no-gap-tab.patch 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 - 35.0-4 +- Gtk3 - fixed tabs rendering + * Wed Jan 14 2015 Martin Stransky - 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 {