cssnode: Refactor node tree modification code

This allows adding more API for it.

It also includes code that tracks modifications and invalidates siblings
and their positions whenever nodes get added or removed.
This commit is contained in:
Benjamin Otte
2015-02-09 22:03:13 +01:00
parent 310f9f40da
commit 507016cafc
2 changed files with 113 additions and 63 deletions

View File

@@ -359,6 +359,110 @@ gtk_css_node_parent_will_be_set (GtkCssNode *node)
GTK_CSS_NODE_GET_CLASS (node)->dequeue_validate (node);
}
static void
gtk_css_node_unlink_from_siblings (GtkCssNode *node)
{
if (GTK_IS_CSS_TRANSIENT_NODE (node))
return;
if (node->previous_sibling)
node->previous_sibling->next_sibling = node->next_sibling;
else
node->parent->first_child = node->next_sibling;
if (node->next_sibling)
node->next_sibling->previous_sibling = node->previous_sibling;
else
node->parent->last_child = node->previous_sibling;
node->previous_sibling = NULL;
node->next_sibling = NULL;
}
static void
gtk_css_node_link_to_siblings (GtkCssNode *node,
GtkCssNode *new_previous)
{
if (GTK_IS_CSS_TRANSIENT_NODE (node))
return;
if (new_previous)
{
node->previous_sibling = new_previous;
node->next_sibling = new_previous->next_sibling;
new_previous->next_sibling = node;
}
else
{
node->next_sibling = node->parent->first_child;
node->parent->first_child = node;
}
if (node->next_sibling)
node->next_sibling->previous_sibling = node;
else
node->parent->last_child = node;
}
static void
gtk_css_node_set_children_changed (GtkCssNode *node)
{
if (node->children_changed)
return;
node->children_changed = TRUE;
gtk_css_node_set_invalid (node, TRUE);
}
static void
gtk_css_node_reposition (GtkCssNode *node,
GtkCssNode *parent,
GtkCssNode *previous)
{
g_assert (! (parent == NULL && previous != NULL));
/* Take a reference here so the whole function has a reference */
g_object_ref (node);
if (node->parent != NULL)
gtk_css_node_unlink_from_siblings (node);
if (node->parent != parent)
{
if (node->parent == NULL)
{
gtk_css_node_parent_will_be_set (node);
}
else
{
g_object_unref (node);
gtk_css_node_set_children_changed (node->parent);
}
node->parent = parent;
if (parent)
{
gtk_css_node_set_children_changed (parent);
g_object_ref (node);
if (node->invalid)
gtk_css_node_set_invalid (parent, TRUE);
}
else
{
gtk_css_node_parent_was_unset (node);
}
}
if (parent)
gtk_css_node_link_to_siblings (node, previous);
gtk_css_node_invalidate (node, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
g_object_unref (node);
}
void
gtk_css_node_set_parent (GtkCssNode *node,
GtkCssNode *parent)
@@ -366,66 +470,7 @@ gtk_css_node_set_parent (GtkCssNode *node,
if (node->parent == parent)
return;
/* Take a reference here so the whole function has a reference */
g_object_ref (node);
if (node->parent != NULL)
{
if (!GTK_IS_CSS_TRANSIENT_NODE (node))
{
if (node->previous_sibling)
node->previous_sibling->next_sibling = node->next_sibling;
else
node->parent->first_child = node->next_sibling;
if (node->next_sibling)
node->next_sibling->previous_sibling = node->previous_sibling;
else
node->parent->last_child = node->previous_sibling;
node->parent->n_children--;
}
node->parent = NULL;
node->next_sibling = NULL;
node->previous_sibling = NULL;
g_object_unref (node);
if (parent == NULL)
gtk_css_node_parent_was_unset (node);
}
if (parent)
{
if (node->parent == NULL)
gtk_css_node_parent_will_be_set (node);
node->parent = parent;
if (!GTK_IS_CSS_TRANSIENT_NODE (node))
{
parent->n_children++;
if (parent->last_child)
{
parent->last_child->next_sibling = node;
node->previous_sibling = parent->last_child;
}
parent->last_child = node;
if (parent->first_child == NULL)
parent->first_child = node;
}
if (node->invalid)
gtk_css_node_set_invalid (parent, TRUE);
}
gtk_css_node_invalidate (node, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
if (node->parent == NULL)
g_object_unref (node);
gtk_css_node_reposition (node, parent, parent ? parent->last_child : NULL);
}
GtkCssNode *
@@ -638,6 +683,11 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode)
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;
@@ -671,11 +721,11 @@ gtk_css_node_validate (GtkCssNode *cssnode,
if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_NO_CSS_CACHE))
change = GTK_CSS_CHANGE_ANY;
gtk_css_node_propagate_pending_changes (cssnode);
if (!cssnode->invalid && change == 0 && _gtk_bitmask_is_empty (parent_changes))
return;
gtk_css_node_propagate_pending_changes (cssnode);
gtk_css_node_set_invalid (cssnode, FALSE);
change = cssnode->pending_changes;

View File

@@ -43,7 +43,6 @@ struct _GtkCssNode
GtkCssNode *next_sibling;
GtkCssNode *first_child;
GtkCssNode *last_child;
guint n_children;
GtkCssNodeDeclaration *decl;
GtkCssStyle *style;
@@ -51,6 +50,7 @@ struct _GtkCssNode
GtkCssChange pending_changes; /* changes that accumulated since the style was last computed */
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 */
};
struct _GtkCssNodeClass