Bug 1308936 - Draw tooltips correctly r=karlt

Tooltip widget is made in GTK3 as following tree:
* Tooltip window
 * Horizontal Box
   * Icon (not supported by Firefox)
   * Label
Each element can be fully styled by CSS of GTK theme so we have to draw all
elements with appropriate offset and full box model.

MozReview-Commit-ID: E9yYd5UWBu4

--HG--
extra : amend_source : 99539e914e8d3fa07f6bed8a315e40c7d593f277
This commit is contained in:
Jan Horak 2016-11-11 11:31:29 +13:00
Родитель 60c50c3f43
Коммит cf2b65692c
3 изменённых файлов: 85 добавлений и 12 удалений

Просмотреть файл

@ -80,8 +80,6 @@ panel[type="arrow"][side="right"] {
tooltip {
-moz-appearance: tooltip;
margin-top: 21px;
/* GTK hardcodes this to 4px */
padding: 4px;
max-width: 40em;
color: InfoText;
font: message-box;

Просмотреть файл

@ -2977,6 +2977,10 @@ moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
ensure_tab_widget();
w = gTabWidget;
break;
case MOZ_GTK_TOOLTIP:
// In GTK 2 the spacing between box is set to 4.
*left = *top = *right = *bottom = 4;
return MOZ_GTK_SUCCESS;
/* These widgets have no borders, since they are not containers. */
case MOZ_GTK_SPLITTER_HORIZONTAL:
case MOZ_GTK_SPLITTER_VERTICAL:
@ -2998,7 +3002,6 @@ moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
case MOZ_GTK_MENUSEPARATOR:
/* These widgets have no borders.*/
case MOZ_GTK_SPINBUTTON:
case MOZ_GTK_TOOLTIP:
case MOZ_GTK_WINDOW:
case MOZ_GTK_RESIZER:
case MOZ_GTK_MENUARROW:

Просмотреть файл

@ -450,6 +450,16 @@ moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width,
padding.top + padding.bottom;
}
static void
moz_gtk_rectangle_inset(GdkRectangle* rect, GtkBorder& aBorder)
{
MOZ_ASSERT(rect);
rect->x += aBorder.left;
rect->y += aBorder.top;
rect->width -= aBorder.left + aBorder.right;
rect->height -= aBorder.top + aBorder.bottom;
}
/* Subtracting margin is used to inset drawing of element which can have margins,
* like scrollbar, scrollbar's trough, thumb and scrollbar's button */
static void
@ -460,10 +470,7 @@ moz_gtk_subtract_margin(GtkStyleContext* style, GdkRectangle* rect)
gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
&margin);
rect->x += margin.left;
rect->y += margin.top;
rect->width -= margin.right + margin.left;
rect->height -= margin.top + margin.bottom;
moz_gtk_rectangle_inset(rect, margin);
}
static gint
@ -1247,12 +1254,57 @@ moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect,
}
static gint
moz_gtk_tooltip_paint(cairo_t *cr, GdkRectangle* rect,
moz_gtk_tooltip_paint(cairo_t *cr, const GdkRectangle* aRect,
GtkTextDirection direction)
{
// Tooltip widget is made in GTK3 as following tree:
// Tooltip window
// Horizontal Box
// Icon (not supported by Firefox)
// Label
// Each element can be fully styled by CSS of GTK theme.
// We have to draw all elements with appropriate offset and right dimensions.
// Tooltip drawing
GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLTIP, direction);
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);
GdkRectangle rect = *aRect;
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);
// Horizontal Box drawing
//
// The box element has hard-coded 6px margin-* GtkWidget properties, which
// are added between the window dimensions and the CSS margin box of the
// horizontal box. The frame of the tooltip window is drawn in the
// 6px margin.
// For drawing Horizontal Box we have to inset drawing area by that 6px
// plus its CSS margin.
GtkStyleContext* boxStyle =
CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0), style);
rect.x += 6;
rect.y += 6;
rect.width -= 12;
rect.height -= 12;
moz_gtk_subtract_margin(boxStyle, &rect);
gtk_render_background(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
gtk_render_frame(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
// Label drawing
GtkBorder padding, border;
gtk_style_context_get_padding(boxStyle, GTK_STATE_FLAG_NORMAL, &padding);
moz_gtk_rectangle_inset(&rect, padding);
gtk_style_context_get_border(boxStyle, GTK_STATE_FLAG_NORMAL, &border);
moz_gtk_rectangle_inset(&rect, border);
GtkStyleContext* labelStyle =
CreateStyleForWidget(gtk_label_new(nullptr), boxStyle);
moz_gtk_draw_styled_frame(labelStyle, cr, &rect, false);
g_object_unref(labelStyle);
g_object_unref(boxStyle);
ReleaseStyleContext(style);
return MOZ_GTK_SUCCESS;
}
@ -2126,8 +2178,28 @@ moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
case MOZ_GTK_TOOLTIP:
{
style = ClaimStyleContext(MOZ_GTK_TOOLTIP);
moz_gtk_add_style_border(style, left, top, right, bottom);
moz_gtk_add_style_padding(style, left, top, right, bottom);
// In GTK 3 there are 6 pixels of additional margin around the box.
// See details there:
// https://github.com/GNOME/gtk/blob/5ea69a136bd7e4970b3a800390e20314665aaed2/gtk/ui/gtktooltipwindow.ui#L11
*left = *right = *top = *bottom = 6;
// We also need to add margin/padding/borders from Tooltip content.
// Tooltip contains horizontal box, where icon and label is put.
// We ignore icon as long as we don't have support for it.
GtkStyleContext* boxStyle =
CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0),
style);
moz_gtk_add_margin_border_padding(boxStyle,
left, top, right, bottom);
GtkStyleContext* labelStyle =
CreateStyleForWidget(gtk_label_new(nullptr), boxStyle);
moz_gtk_add_margin_border_padding(labelStyle,
left, top, right, bottom);
g_object_unref(labelStyle);
g_object_unref(boxStyle);
ReleaseStyleContext(style);
return MOZ_GTK_SUCCESS;
}