summaryrefslogtreecommitdiff
path: root/gtk/gtkcssnode.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2015-12-16 19:48:30 +0100
committerBenjamin Otte <otte@redhat.com>2015-12-16 19:55:50 +0100
commit2e362eafc7a22e007fddb4ee9c76dfffdbbf02b7 (patch)
treeff56729e797cc340e4c4471f573591d24389765c /gtk/gtkcssnode.c
parent36653bea4189221c1b3d391890793f50fde3c758 (diff)
downloadgtk+-2e362eafc7a22e007fddb4ee9c76dfffdbbf02b7.tar.gz
cssnode: Redo first/last-child change tracking
Invisible nodes don't change the first/last-child status of the nodes after/before them. That means we don't have to just check the state of the adjacent node when modifying this state, but all their siblings until we hit a visible node. The same way, a node is not the first child if it has no previous sibling, it is the first child if it has no previous visible sibling. This is important for caching in the global lookup cache.
Diffstat (limited to 'gtk/gtkcssnode.c')
-rw-r--r--gtk/gtkcssnode.c72
1 files changed, 62 insertions, 10 deletions
diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c
index 738d1e9116..b129c01df2 100644
--- a/gtk/gtkcssnode.c
+++ b/gtk/gtkcssnode.c
@@ -253,6 +253,36 @@ gtk_css_node_finalize (GObject *object)
G_OBJECT_CLASS (gtk_css_node_parent_class)->finalize (object);
}
+static gboolean
+gtk_css_node_is_first_child (GtkCssNode *node)
+{
+ GtkCssNode *iter;
+
+ for (iter = node->previous_sibling;
+ iter != NULL;
+ iter = iter->previous_sibling)
+ {
+ if (iter->visible)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+gtk_css_node_is_last_child (GtkCssNode *node)
+{
+ GtkCssNode *iter;
+
+ for (iter = node->next_sibling;
+ iter != NULL;
+ iter = iter->next_sibling)
+ {
+ if (iter->visible)
+ return FALSE;
+ }
+ return TRUE;
+}
+
#define UNPACK_DECLARATION(packed) ((GtkCssNodeDeclaration *) (GPOINTER_TO_SIZE (packed) & ~0x3))
#define UNPACK_FLAGS(packed) (GPOINTER_TO_SIZE (packed) & 0x3)
#define PACK(decl, first_child, last_child) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (decl) | ((first_child) ? 0x2 : 0) | ((last_child) ? 0x1 : 0))
@@ -292,8 +322,8 @@ lookup_in_global_parent_cache (GtkCssNode *node,
style = g_hash_table_lookup (cache,
PACK (decl,
- gtk_css_node_get_previous_sibling (node) == NULL,
- gtk_css_node_get_next_sibling (node) == NULL));
+ gtk_css_node_is_first_child (node),
+ gtk_css_node_is_last_child (node)));
return style;
}
@@ -376,8 +406,8 @@ store_in_global_parent_cache (GtkCssNode *node,
g_hash_table_insert (cache,
PACK (gtk_css_node_declaration_ref ((GtkCssNodeDeclaration *) decl),
- gtk_css_node_get_previous_sibling (node) == NULL,
- gtk_css_node_get_next_sibling (node) == NULL),
+ gtk_css_node_is_first_child (node),
+ gtk_css_node_is_last_child (node)),
g_object_ref (style));
}
@@ -1071,6 +1101,8 @@ void
gtk_css_node_set_visible (GtkCssNode *cssnode,
gboolean visible)
{
+ GtkCssNode *iter;
+
if (cssnode->visible == visible)
return;
@@ -1094,14 +1126,34 @@ gtk_css_node_set_visible (GtkCssNode *cssnode,
}
if (cssnode->next_sibling)
- gtk_css_node_invalidate (cssnode->next_sibling, GTK_CSS_CHANGE_ANY_SIBLING
- | GTK_CSS_CHANGE_NTH_CHILD
- | (cssnode->previous_sibling ? 0 : GTK_CSS_CHANGE_FIRST_CHILD));
-
+ {
+ gtk_css_node_invalidate (cssnode->next_sibling, GTK_CSS_CHANGE_ANY_SIBLING | GTK_CSS_CHANGE_NTH_CHILD);
+ if (gtk_css_node_is_first_child (cssnode))
+ {
+ for (iter = cssnode->next_sibling;
+ iter != NULL;
+ iter = iter->next_sibling)
+ {
+ gtk_css_node_invalidate (iter, GTK_CSS_CHANGE_FIRST_CHILD);
+ if (iter->visible)
+ break;
+ }
+ }
+ }
+
if (cssnode->previous_sibling)
{
- if (cssnode->next_sibling)
- gtk_css_node_invalidate (cssnode->previous_sibling, GTK_CSS_CHANGE_LAST_CHILD);
+ if (gtk_css_node_is_last_child (cssnode))
+ {
+ for (iter = cssnode->previous_sibling;
+ iter != NULL;
+ iter = iter->previous_sibling)
+ {
+ gtk_css_node_invalidate (iter, GTK_CSS_CHANGE_LAST_CHILD);
+ if (iter->visible)
+ break;
+ }
+ }
gtk_css_node_invalidate (cssnode->parent->first_child, GTK_CSS_CHANGE_NTH_LAST_CHILD);
}
}