widget: Cache clip from creating render node

When the clip changes that is passed to a snapshot function, we need to
create eventual cached render nodes because they might not have drawn
their whole area before.

Fixes issues with redrawing when scrolling.
This commit is contained in:
Benjamin Otte 2018-03-31 17:52:47 +02:00
parent 278ab3c4de
commit 4bf90633ea
4 changed files with 49 additions and 8 deletions

View File

@ -1594,6 +1594,23 @@ gtk_snapshot_append_color (GtkSnapshot *snapshot,
gsk_render_node_unref (node);
}
gboolean
gtk_snapshot_get_clip (GtkSnapshot *snapshot,
graphene_rect_t *out_clip)
{
const GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
if (!current_state->has_clip)
return FALSE;
graphene_rect_offset_r (&current_state->clip,
- current_state->translate_x,
- current_state->translate_y,
out_clip);
return TRUE;
}
/**
* gtk_snapshot_clips_rect:
* @snapshot: a #GtkSnapshot

View File

@ -99,11 +99,13 @@ struct _GtkSnapshotClass {
GObjectClass parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */
};
GtkSnapshot * gtk_snapshot_new_child (GtkSnapshot *parent,
const char *name,
...) G_GNUC_PRINTF (2, 3);
void gtk_snapshot_append_node_internal (GtkSnapshot *snapshot,
GskRenderNode *node);
GtkSnapshot * gtk_snapshot_new_child (GtkSnapshot *parent,
const char *name,
...) G_GNUC_PRINTF (2, 3);
void gtk_snapshot_append_node_internal (GtkSnapshot *snapshot,
GskRenderNode *node);
gboolean gtk_snapshot_get_clip (GtkSnapshot *snapshot,
graphene_rect_t *out_clip);
G_END_DECLS

View File

@ -4021,6 +4021,7 @@ gtk_widget_queue_draw (GtkWidget *widget)
priv->draw_needed = TRUE;
g_clear_pointer (&priv->render_node, gsk_render_node_unref);
priv->render_node_has_clip = FALSE;
gtk_widget_invalidate_paintable_contents (widget);
if (_gtk_widget_get_has_surface (widget) &&
_gtk_widget_get_realized (widget))
@ -13816,6 +13817,8 @@ gtk_widget_snapshot (GtkWidget *widget,
{
GtkWidgetPrivate *priv = widget->priv;
graphene_rect_t offset_clip;
graphene_rect_t clip;
gboolean has_clip;
double opacity;
if (!_gtk_widget_is_drawable (widget))
@ -13841,13 +13844,28 @@ gtk_widget_snapshot (GtkWidget *widget,
if (opacity <= 0.0)
return;
if (priv->draw_needed)
has_clip = gtk_snapshot_get_clip (snapshot, &clip);
if (priv->draw_needed ||
(priv->render_node_has_clip && (!has_clip || !graphene_rect_contains_rect (&priv->render_node_clip, &clip))))
{
GskRenderNode *render_node;
render_node = gtk_widget_create_render_node (widget, snapshot);
/* This can happen when nested drawing happens and a widget contains itself */
/* This can happen when nested drawing happens and a widget contains itself
* or when we replace a clipped area */
g_clear_pointer (&priv->render_node, gsk_render_node_unref);
priv->render_node = render_node;
if (has_clip)
{
priv->render_node_clip = clip;
priv->render_node_has_clip = TRUE;
}
else
{
priv->render_node_has_clip = FALSE;
}
priv->draw_needed = FALSE;
}

View File

@ -78,6 +78,7 @@ struct _GtkWidgetPrivate
/* Queue-draw related flags */
guint draw_needed : 1;
guint render_node_has_clip : 1;
/* Expand-related flags */
guint need_compute_expand : 1; /* Need to recompute computed_[hv]_expand */
@ -145,8 +146,11 @@ struct _GtkWidgetPrivate
/* The widget's requested sizes */
SizeRequestCache requests;
/* The render node we draw or %NULL if not yet created. */
/* The render node we draw or %NULL if not yet created.*/
GskRenderNode *render_node;
/* The clip that existed when the render node was drawn
* Ignored when render_node_has_clip == FALSE */
graphene_rect_t render_node_clip;
GSList *paintables;