464 lines
20 KiB
Diff
464 lines
20 KiB
Diff
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 {
|