gadget: Be careful in geometry calculations

Margins can be negative, and if we are not careful, then
content+padding+margin can end up with negative dimensions,
which can upset pixman and others. This commit ensures
that a gadget will not request or draw boxes with negative
dimensions, and get_border_allocation and get_content_allocation
will not return boxes with negative dimensions.

This fixes a crash in the paned separator drawing code that
can be reproduced by setting separator padding to 0.

https://bugzilla.gnome.org/show_bug.cgi?id=759657
This commit is contained in:
Matthias Clasen 2016-02-12 22:26:04 -05:00
parent 71559c603e
commit 51af70495a

View File

@ -552,7 +552,7 @@ gtk_css_gadget_get_preferred_size (GtkCssGadget *gadget,
} }
if (for_size > -1) if (for_size > -1)
for_size -= extra_opposite; for_size = MAX (0, for_size - extra_opposite);
if (minimum_baseline) if (minimum_baseline)
*minimum_baseline = -1; *minimum_baseline = -1;
@ -570,13 +570,13 @@ gtk_css_gadget_get_preferred_size (GtkCssGadget *gadget,
*minimum = MAX (min_size, *minimum); *minimum = MAX (min_size, *minimum);
*natural = MAX (min_size, *natural); *natural = MAX (min_size, *natural);
*minimum += extra_size; *minimum = MAX (0, *minimum + extra_size);
*natural += extra_size; *natural = MAX (0, *natural + extra_size);
if (minimum_baseline && *minimum_baseline > -1) if (minimum_baseline && *minimum_baseline > -1)
*minimum_baseline += extra_baseline; *minimum_baseline = MAX (0, *minimum_baseline + extra_baseline);
if (natural_baseline && *natural_baseline > -1) if (natural_baseline && *natural_baseline > -1)
*natural_baseline += extra_baseline; *natural_baseline = MAX (0, *natural_baseline + extra_baseline);
} }
/** /**
@ -632,6 +632,7 @@ gtk_css_gadget_allocate (GtkCssGadget *gadget,
content_allocation.y = allocation->y + extents.top; content_allocation.y = allocation->y + extents.top;
content_allocation.width = allocation->width - extents.left - extents.right; content_allocation.width = allocation->width - extents.left - extents.right;
content_allocation.height = allocation->height - extents.top - extents.bottom; content_allocation.height = allocation->height - extents.top - extents.bottom;
if (baseline >= 0) if (baseline >= 0)
baseline -= extents.top; baseline -= extents.top;
@ -663,8 +664,8 @@ gtk_css_gadget_allocate (GtkCssGadget *gadget,
out_clip->x = allocation->x + margin.left - shadow.left; out_clip->x = allocation->x + margin.left - shadow.left;
out_clip->y = allocation->y + margin.top - shadow.top; out_clip->y = allocation->y + margin.top - shadow.top;
out_clip->width = allocation->width - margin.left - margin.right + shadow.left + shadow.right; out_clip->width = MAX (0, allocation->width - margin.left - margin.right + shadow.left + shadow.right);
out_clip->height = allocation->height - margin.top - margin.bottom + shadow.top + shadow.bottom; out_clip->height = MAX (0, allocation->height - margin.top - margin.bottom + shadow.top + shadow.bottom);
if (content_clip.width > 0 && content_clip.height > 0) if (content_clip.width > 0 && content_clip.height > 0)
gdk_rectangle_union (&content_clip, out_clip, out_clip); gdk_rectangle_union (&content_clip, out_clip, out_clip);
@ -689,7 +690,7 @@ gtk_css_gadget_draw (GtkCssGadget *gadget,
{ {
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget); GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
GtkBorder margin, border, padding; GtkBorder margin, border, padding;
gboolean draw_focus; gboolean draw_focus = FALSE;
GtkCssStyle *style; GtkCssStyle *style;
int x, y, width, height; int x, y, width, height;
int contents_x, contents_y, contents_width, contents_height; int contents_x, contents_y, contents_width, contents_height;
@ -735,6 +736,7 @@ gtk_css_gadget_draw (GtkCssGadget *gadget,
contents_width = width - margin.left - margin.right - border.left - border.right - padding.left - padding.right; contents_width = width - margin.left - margin.right - border.left - border.right - padding.left - padding.right;
contents_height = height - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom; contents_height = height - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom;
if (contents_width > 0 && contents_height > 0)
draw_focus = GTK_CSS_GADGET_GET_CLASS (gadget)->draw (gadget, draw_focus = GTK_CSS_GADGET_GET_CLASS (gadget)->draw (gadget,
cr, cr,
contents_x, contents_y, contents_x, contents_y,
@ -871,8 +873,8 @@ gtk_css_gadget_get_border_allocation (GtkCssGadget *gadget,
{ {
allocation->x = priv->allocated_size.x + margin.left; allocation->x = priv->allocated_size.x + margin.left;
allocation->y = priv->allocated_size.y + margin.top; allocation->y = priv->allocated_size.y + margin.top;
allocation->width = priv->allocated_size.width - margin.left - margin.right; allocation->width = MAX (0, priv->allocated_size.width - margin.left - margin.right);
allocation->height = priv->allocated_size.height - margin.top - margin.bottom; allocation->height = MAX (0, priv->allocated_size.height - margin.top - margin.bottom);
} }
if (baseline) if (baseline)
{ {
@ -916,9 +918,10 @@ gtk_css_gadget_get_content_allocation (GtkCssGadget *gadget,
{ {
allocation->x = priv->allocated_size.x + extents.left; allocation->x = priv->allocated_size.x + extents.left;
allocation->y = priv->allocated_size.y + extents.top; allocation->y = priv->allocated_size.y + extents.top;
allocation->width = priv->allocated_size.width - extents.left - extents.right; allocation->width = MAX (0, priv->allocated_size.width - extents.left - extents.right);
allocation->height = priv->allocated_size.height - extents.top - extents.bottom; allocation->height = MAX (0, priv->allocated_size.height - extents.top - extents.bottom);
} }
if (baseline) if (baseline)
{ {
if (priv->allocated_baseline >= 0) if (priv->allocated_baseline >= 0)