cssnode: Implement a way to properly track invalidations
See the comment in gtkcssnodeprivate.h for how this works.
This commit is contained in:
102
gtk/gtkcssnode.c
102
gtk/gtkcssnode.c
@ -373,6 +373,22 @@ gtk_css_node_set_children_changed (GtkCssNode *node)
|
|||||||
gtk_css_node_set_invalid (node, TRUE);
|
gtk_css_node_set_invalid (node, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_css_node_invalidate_style (GtkCssNode *cssnode)
|
||||||
|
{
|
||||||
|
if (cssnode->style_is_invalid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cssnode->style_is_invalid = TRUE;
|
||||||
|
gtk_css_node_set_invalid (cssnode, TRUE);
|
||||||
|
|
||||||
|
if (cssnode->first_child)
|
||||||
|
gtk_css_node_invalidate_style (cssnode->first_child);
|
||||||
|
|
||||||
|
if (cssnode->next_sibling)
|
||||||
|
gtk_css_node_invalidate_style (cssnode->next_sibling);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_css_node_reposition (GtkCssNode *node,
|
gtk_css_node_reposition (GtkCssNode *node,
|
||||||
GtkCssNode *parent,
|
GtkCssNode *parent,
|
||||||
@ -383,6 +399,9 @@ gtk_css_node_reposition (GtkCssNode *node,
|
|||||||
/* Take a reference here so the whole function has a reference */
|
/* Take a reference here so the whole function has a reference */
|
||||||
g_object_ref (node);
|
g_object_ref (node);
|
||||||
|
|
||||||
|
if (node->next_sibling)
|
||||||
|
gtk_css_node_invalidate_style (node->next_sibling);
|
||||||
|
|
||||||
if (node->parent != NULL)
|
if (node->parent != NULL)
|
||||||
gtk_css_node_unlink_from_siblings (node);
|
gtk_css_node_unlink_from_siblings (node);
|
||||||
|
|
||||||
@ -419,6 +438,9 @@ gtk_css_node_reposition (GtkCssNode *node,
|
|||||||
if (parent)
|
if (parent)
|
||||||
gtk_css_node_link_to_siblings (node, previous);
|
gtk_css_node_link_to_siblings (node, previous);
|
||||||
|
|
||||||
|
if (node->next_sibling)
|
||||||
|
gtk_css_node_invalidate_style (node->next_sibling);
|
||||||
|
|
||||||
gtk_css_node_invalidate (node, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
|
gtk_css_node_invalidate (node, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
|
||||||
|
|
||||||
g_object_unref (node);
|
g_object_unref (node);
|
||||||
@ -504,13 +526,49 @@ gtk_css_node_set_style (GtkCssNode *cssnode,
|
|||||||
cssnode->style = style;
|
cssnode->style = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkCssStyle *
|
static void
|
||||||
gtk_css_node_get_style (GtkCssNode *cssnode)
|
gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode)
|
||||||
|
{
|
||||||
|
GtkCssChange change, child_change;
|
||||||
|
GtkCssNode *child;
|
||||||
|
|
||||||
|
if (!cssnode->invalid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
change = _gtk_css_change_for_child (cssnode->pending_changes);
|
||||||
|
if (cssnode->children_changed)
|
||||||
|
{
|
||||||
|
change |= GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_ANY_SIBLING;
|
||||||
|
cssnode->children_changed = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (child = gtk_css_node_get_first_child (cssnode);
|
||||||
|
child;
|
||||||
|
child = gtk_css_node_get_next_sibling (child))
|
||||||
|
{
|
||||||
|
child_change = child->pending_changes;
|
||||||
|
gtk_css_node_invalidate (child, change);
|
||||||
|
if (child->visible)
|
||||||
|
change |= _gtk_css_change_for_sibling (child_change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_css_node_ensure_style (GtkCssNode *cssnode)
|
||||||
{
|
{
|
||||||
GtkCssStyle *new_style;
|
GtkCssStyle *new_style;
|
||||||
|
|
||||||
if (cssnode->pending_changes)
|
if (!cssnode->style_is_invalid)
|
||||||
{
|
return;
|
||||||
|
|
||||||
|
if (cssnode->parent)
|
||||||
|
gtk_css_node_ensure_style (cssnode->parent);
|
||||||
|
|
||||||
|
if (cssnode->previous_sibling)
|
||||||
|
gtk_css_node_ensure_style (cssnode->previous_sibling);
|
||||||
|
|
||||||
|
gtk_css_node_propagate_pending_changes (cssnode);
|
||||||
|
|
||||||
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
|
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
|
||||||
cssnode->pending_changes,
|
cssnode->pending_changes,
|
||||||
cssnode->style);
|
cssnode->style);
|
||||||
@ -520,7 +578,14 @@ gtk_css_node_get_style (GtkCssNode *cssnode)
|
|||||||
g_object_unref (new_style);
|
g_object_unref (new_style);
|
||||||
cssnode->pending_changes = 0;
|
cssnode->pending_changes = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
cssnode->style_is_invalid = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkCssStyle *
|
||||||
|
gtk_css_node_get_style (GtkCssNode *cssnode)
|
||||||
|
{
|
||||||
|
gtk_css_node_ensure_style (cssnode);
|
||||||
|
|
||||||
return cssnode->style;
|
return cssnode->style;
|
||||||
}
|
}
|
||||||
@ -674,31 +739,7 @@ gtk_css_node_invalidate (GtkCssNode *cssnode,
|
|||||||
|
|
||||||
GTK_CSS_NODE_GET_CLASS (cssnode)->invalidate (cssnode);
|
GTK_CSS_NODE_GET_CLASS (cssnode)->invalidate (cssnode);
|
||||||
|
|
||||||
gtk_css_node_set_invalid (cssnode, TRUE);
|
gtk_css_node_invalidate_style (cssnode);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode)
|
|
||||||
{
|
|
||||||
GtkCssChange change;
|
|
||||||
GtkCssNode *child;
|
|
||||||
|
|
||||||
if (!cssnode->invalid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
change = _gtk_css_change_for_child (cssnode->pending_changes);
|
|
||||||
if (cssnode->children_changed)
|
|
||||||
{
|
|
||||||
change |= GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_ANY_SIBLING;
|
|
||||||
cssnode->children_changed = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (child = gtk_css_node_get_first_child (cssnode);
|
|
||||||
child;
|
|
||||||
child = gtk_css_node_get_next_sibling (child))
|
|
||||||
{
|
|
||||||
gtk_css_node_invalidate (child, change);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -735,6 +776,7 @@ gtk_css_node_validate (GtkCssNode *cssnode,
|
|||||||
|
|
||||||
change = cssnode->pending_changes;
|
change = cssnode->pending_changes;
|
||||||
cssnode->pending_changes = 0;
|
cssnode->pending_changes = 0;
|
||||||
|
cssnode->style_is_invalid = FALSE;
|
||||||
|
|
||||||
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->validate (cssnode, cssnode->style, timestamp, change, parent_changed);
|
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->validate (cssnode, cssnode->style, timestamp, change, parent_changed);
|
||||||
if (new_style)
|
if (new_style)
|
||||||
|
@ -52,6 +52,12 @@ struct _GtkCssNode
|
|||||||
guint visible :1; /* node will be skipped when validating or computing styles */
|
guint visible :1; /* node will be skipped when validating or computing styles */
|
||||||
guint invalid :1; /* node or a child needs to be validated (even if just for animation) */
|
guint invalid :1; /* node or a child needs to be validated (even if just for animation) */
|
||||||
guint children_changed :1; /* the children changed since last validation */
|
guint children_changed :1; /* the children changed since last validation */
|
||||||
|
/* Two invariants hold for this variable:
|
||||||
|
* style_is_invalid == TRUE => next_sibling->style_is_invalid == TRUE
|
||||||
|
* style_is_invalid == FALSE => first_child->style_is_invalid == TRUE
|
||||||
|
* So if a valid style is computed, one has to previously ensure that the parent's and the previous sibling's style
|
||||||
|
* are valid. This allows both validation and invalidation to run in O(nodes-in-tree) */
|
||||||
|
guint style_is_invalid :1; /* the style needs to be recomputed */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GtkCssNodeClass
|
struct _GtkCssNodeClass
|
||||||
|
Reference in New Issue
Block a user