[gtk+] stylecontext: Split out functionality into custom object



commit 5c2c65912200789c3edd9c574d619b65e398ccb2
Author: Benjamin Otte <otte redhat com>
Date:   Sat Oct 18 05:45:21 2014 +0200

    stylecontext: Split out functionality into custom object
    
    GtkCssNodeDeclaration is a new struct with copy-on-write semantics.
    
    It encapsulated the properties used to define a node in the CSS tree.
    
    The idea is to use it in various places for caching, in particular as
    key in hash tables.

 gtk/Makefile.am                    |    2 +
 gtk/gtkcssnodedeclaration.c        |  528 ++++++++++++++++++++++++++++++++++++
 gtk/gtkcssnodedeclarationprivate.h |   67 +++++
 gtk/gtkstylecontext.c              |  357 ++++---------------------
 4 files changed, 648 insertions(+), 306 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index ee32932..41943da 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -558,6 +558,7 @@ gtk_private_h_sources =             \
        gtkcsskeyframesprivate.h        \
        gtkcsslookupprivate.h   \
        gtkcssmatcherprivate.h  \
+       gtkcssnodedeclarationprivate.h  \
        gtkcssnumbervalueprivate.h      \
        gtkcssparserprivate.h   \
        gtkcsspositionvalueprivate.h    \
@@ -881,6 +882,7 @@ gtk_base_c_sources =                \
        gtkcsskeyframes.c       \
        gtkcsslookup.c          \
        gtkcssmatcher.c         \
+       gtkcssnodedeclaration.c \
        gtkcssnumbervalue.c     \
        gtkcssparser.c          \
        gtkcsspositionvalue.c   \
diff --git a/gtk/gtkcssnodedeclaration.c b/gtk/gtkcssnodedeclaration.c
new file mode 100644
index 0000000..b5874ff
--- /dev/null
+++ b/gtk/gtkcssnodedeclaration.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright © 2014 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkcssnodedeclarationprivate.h"
+
+#include <string.h>
+
+typedef struct _GtkRegion GtkRegion;
+
+struct _GtkRegion
+{
+  GQuark class_quark;
+  GtkRegionFlags flags;
+};
+
+struct _GtkCssNodeDeclaration {
+  guint refcount;
+  GtkJunctionSides junction_sides;
+  GtkStateFlags state;
+  guint n_classes;
+  guint n_regions;
+  /* GQuark classes[n_classes]; */
+  /* GtkRegion region[n_regions]; */
+};
+
+static inline GQuark *
+get_classes (const GtkCssNodeDeclaration *decl)
+{
+  return (GQuark *) (decl + 1);
+}
+
+static inline GtkRegion *
+get_regions (const GtkCssNodeDeclaration *decl)
+{
+  return (GtkRegion *) (get_classes (decl) + decl->n_classes);
+}
+
+static inline gsize
+sizeof_node (guint n_classes,
+             guint n_regions)
+{
+  return sizeof (GtkCssNodeDeclaration)
+       + sizeof (GQuark) * n_classes
+       + sizeof (GtkRegion) * n_regions;
+}
+
+static inline gsize
+sizeof_this_node (GtkCssNodeDeclaration *decl)
+{
+  return sizeof_node (decl->n_classes, decl->n_regions);
+}
+
+static void
+gtk_css_node_declaration_make_writable (GtkCssNodeDeclaration **decl)
+{
+  if ((*decl)->refcount == 1)
+    return;
+
+  (*decl)->refcount--;
+
+  *decl = g_memdup (*decl, sizeof_this_node (*decl));
+  (*decl)->refcount = 1;
+}
+
+static void
+gtk_css_node_declaration_make_writable_resize (GtkCssNodeDeclaration **decl,
+                                               gsize                   offset,
+                                               gsize                   bytes_added,
+                                               gsize                   bytes_removed)
+{
+  gsize old_size = sizeof_this_node (*decl);
+  gsize new_size = old_size + bytes_added - bytes_removed;
+
+  if ((*decl)->refcount == 1)
+    {
+      if (bytes_removed > 0 && old_size - offset - bytes_removed > 0)
+        memmove (((char *) *decl) + offset + bytes_removed, ((char *) *decl) + offset, old_size - offset - 
bytes_removed);
+      *decl = g_realloc (*decl, new_size);
+      if (bytes_added > 0 && old_size - offset > 0)
+        memmove (((char *) *decl) + offset + bytes_added, ((char *) *decl) + offset, old_size - offset);
+    }
+  else
+    {
+      GtkCssNodeDeclaration *old = *decl;
+
+      old->refcount--;
+  
+      *decl = g_malloc (new_size);
+      memcpy (*decl, old, offset);
+      if (old_size - offset - bytes_removed > 0)
+        memcpy (((char *) *decl) + offset + bytes_added, ((char *) old) + offset + bytes_removed, old_size - 
offset - bytes_removed);
+      (*decl)->refcount = 1;
+    }
+}
+
+GtkCssNodeDeclaration *
+gtk_css_node_declaration_new (void)
+{
+  static GtkCssNodeDeclaration empty = {
+    1, /* need to own a ref ourselves so the copy-on-write path kicks in when people change things */
+    0,
+    0,
+    0,
+    0
+  };
+
+  return gtk_css_node_declaration_ref (&empty);
+}
+
+GtkCssNodeDeclaration *
+gtk_css_node_declaration_ref (GtkCssNodeDeclaration *decl)
+{
+  decl->refcount++;
+
+  return decl;
+}
+
+void
+gtk_css_node_declaration_unref (GtkCssNodeDeclaration *decl)
+{
+  decl->refcount--;
+  if (decl->refcount > 0)
+    return;
+
+  g_free (decl);
+}
+
+gboolean
+gtk_css_node_declaration_set_junction_sides (GtkCssNodeDeclaration **decl,
+                                             GtkJunctionSides        junction_sides)
+{
+  if ((*decl)->junction_sides == junction_sides)
+    return FALSE;
+  
+  gtk_css_node_declaration_make_writable (decl);
+  (*decl)->junction_sides = junction_sides;
+
+  return TRUE;
+}
+
+GtkJunctionSides
+gtk_css_node_declaration_get_junction_sides (const GtkCssNodeDeclaration *decl)
+{
+  return decl->junction_sides;
+}
+
+gboolean
+gtk_css_node_declaration_set_state (GtkCssNodeDeclaration **decl,
+                                    GtkStateFlags           state)
+{
+  if ((*decl)->state == state)
+    return FALSE;
+  
+  gtk_css_node_declaration_make_writable (decl);
+  (*decl)->state = state;
+
+  return TRUE;
+}
+
+GtkStateFlags
+gtk_css_node_declaration_get_state (const GtkCssNodeDeclaration *decl)
+{
+  return decl->state;
+}
+
+static gboolean
+find_class (const GtkCssNodeDeclaration *decl,
+            GQuark                       class_quark,
+            guint                       *position)
+{
+  gint min, max, mid;
+  gboolean found = FALSE;
+  GQuark *classes;
+  guint pos;
+
+  if (position)
+    *position = 0;
+
+  if (decl->n_classes == 0)
+    return FALSE;
+
+  min = 0;
+  max = decl->n_classes - 1;
+  classes = get_classes (decl);
+
+  do
+    {
+      GQuark item;
+
+      mid = (min + max) / 2;
+      item = classes[mid];
+
+      if (class_quark == item)
+        {
+          found = TRUE;
+          pos = mid;
+          break;
+        }
+      else if (class_quark > item)
+        min = pos = mid + 1;
+      else
+        {
+          max = mid - 1;
+          pos = mid;
+        }
+    }
+  while (min <= max);
+
+  if (position)
+    *position = pos;
+
+  return found;
+}
+
+gboolean
+gtk_css_node_declaration_add_class (GtkCssNodeDeclaration **decl,
+                                    GQuark                  class_quark)
+{
+  guint pos;
+
+  if (find_class (*decl, class_quark, &pos))
+    return FALSE;
+
+  gtk_css_node_declaration_make_writable_resize (decl,
+                                                 (char *) &get_classes (*decl)[pos] - (char *) *decl,
+                                                 sizeof (GQuark),
+                                                 0);
+  (*decl)->n_classes++;
+  get_classes(*decl)[pos] = class_quark;
+
+  return TRUE;
+}
+
+gboolean
+gtk_css_node_declaration_remove_class (GtkCssNodeDeclaration **decl,
+                                       GQuark                  class_quark)
+{
+  guint pos;
+
+  if (!find_class (*decl, class_quark, &pos))
+    return FALSE;
+
+  gtk_css_node_declaration_make_writable_resize (decl,
+                                                 (char *) &get_classes (*decl)[pos] - (char *) *decl,
+                                                 0,
+                                                 sizeof (GQuark));
+  (*decl)->n_classes--;
+
+  return TRUE;
+}
+
+gboolean
+gtk_css_node_declaration_has_class (const GtkCssNodeDeclaration *decl,
+                                    GQuark                       class_quark)
+{
+  return find_class (decl, class_quark, NULL);
+}
+
+GList *
+gtk_css_node_declaration_list_classes (const GtkCssNodeDeclaration *decl)
+{
+  GQuark *classes;
+  GList *result;
+  guint i;
+
+  classes = get_classes (decl);
+  result = NULL;
+
+  for (i = 0; i < decl->n_classes; i++)
+    {
+      result = g_list_prepend (result, GUINT_TO_POINTER (classes[i]));
+    }
+
+  return result;
+}
+
+static gboolean
+find_region (const GtkCssNodeDeclaration *decl,
+             GQuark                       region_quark,
+             guint                       *position)
+{
+  gint min, max, mid;
+  gboolean found = FALSE;
+  GtkRegion *regions;
+  guint pos;
+
+  if (position)
+    *position = 0;
+
+  if (decl->n_regions == 0)
+    return FALSE;
+
+  min = 0;
+  max = decl->n_regions - 1;
+  regions = get_regions (decl);
+
+  do
+    {
+      GQuark item;
+
+      mid = (min + max) / 2;
+      item = regions[mid].class_quark;
+
+      if (region_quark == item)
+        {
+          found = TRUE;
+          pos = mid;
+          break;
+        }
+      else if (region_quark > item)
+        min = pos = mid + 1;
+      else
+        {
+          max = mid - 1;
+          pos = mid;
+        }
+    }
+  while (min <= max);
+
+  if (position)
+    *position = pos;
+
+  return found;
+}
+
+gboolean
+gtk_css_node_declaration_add_region (GtkCssNodeDeclaration **decl,
+                                     GQuark                  region_quark,
+                                     GtkRegionFlags          flags)
+{
+  GtkRegion *regions;
+  guint pos;
+
+  if (find_region (*decl, region_quark, &pos))
+    return FALSE;
+
+  gtk_css_node_declaration_make_writable_resize (decl,
+                                                 (char *) &get_regions (*decl)[pos] - (char *) *decl,
+                                                 sizeof (GtkRegion),
+                                                 0);
+  (*decl)->n_regions++;
+  regions = get_regions(*decl);
+  regions[pos].class_quark = region_quark;
+  regions[pos].flags = flags;
+
+  return TRUE;
+}
+
+gboolean
+gtk_css_node_declaration_remove_region (GtkCssNodeDeclaration **decl,
+                                        GQuark                  region_quark)
+{
+  guint pos;
+
+  if (!find_region (*decl, region_quark, &pos))
+    return FALSE;
+
+  gtk_css_node_declaration_make_writable_resize (decl,
+                                                 (char *) &get_regions (*decl)[pos] - (char *) *decl,
+                                                 0,
+                                                 sizeof (GtkRegion));
+  (*decl)->n_regions--;
+
+  return TRUE;
+}
+
+gboolean
+gtk_css_node_declaration_has_region (const GtkCssNodeDeclaration  *decl,
+                                     GQuark                        region_quark,
+                                     GtkRegionFlags               *flags_return)
+{
+  guint pos;
+
+  if (!find_region (decl, region_quark, &pos))
+    {
+      if (flags_return)
+        *flags_return = 0;
+      return FALSE;
+    }
+
+  if (flags_return)
+    *flags_return = get_regions (decl)[pos].flags;
+
+  return TRUE;
+}
+
+GList *
+gtk_css_node_declaration_list_regions (const GtkCssNodeDeclaration *decl)
+{
+  GtkRegion *regions;
+  GList *result;
+  guint i;
+
+  regions = get_regions (decl);
+  result = NULL;
+
+  for (i = 0; i < decl->n_regions; i++)
+    {
+      result = g_list_prepend (result, GUINT_TO_POINTER (regions[i].class_quark));
+    }
+
+  return result;
+}
+
+guint
+gtk_css_node_declaration_hash (gconstpointer elem)
+{
+  const GtkCssNodeDeclaration *decl = elem;
+  GQuark *classes;
+  GtkRegion *regions;
+  guint hash, i;
+  
+  hash = 0;
+
+  classes = get_classes (decl);
+  for (i = 0; i < decl->n_classes; i++)
+    {
+      hash <<= 5;
+      hash += classes[i];
+    }
+
+  regions = get_regions (decl);
+  for (i = 0; i < decl->n_regions; i++)
+    {
+      hash <<= 5;
+      hash += regions[i].class_quark;
+      hash += regions[i].flags;
+    }
+
+  hash ^= ((guint) decl->junction_sides) << (sizeof (guint) * 8 - 5);
+  hash ^= decl->state;
+
+  return hash;
+}
+
+gboolean
+gtk_css_node_declaration_equal (gconstpointer elem1,
+                                gconstpointer elem2)
+{
+  const GtkCssNodeDeclaration *decl1 = elem1;
+  const GtkCssNodeDeclaration *decl2 = elem2;
+  GQuark *classes1, *classes2;
+  GtkRegion *regions1, *regions2;
+  guint i;
+
+  if (decl1 == decl2)
+    return TRUE;
+
+  if (decl1->state != decl2->state)
+    return FALSE;
+
+  if (decl1->n_classes != decl2->n_classes)
+    return FALSE;
+
+  classes1 = get_classes (decl1);
+  classes2 = get_classes (decl2);
+  for (i = 0; i < decl1->n_classes; i++)
+    {
+      if (classes1[i] != classes2[i])
+        return FALSE;
+    }
+
+  if (decl1->n_regions != decl2->n_regions)
+    return FALSE;
+
+  regions1 = get_regions (decl1);
+  regions2 = get_regions (decl2);
+  for (i = 0; i < decl1->n_regions; i++)
+    {
+      if (regions1[i].class_quark != regions2[i].class_quark ||
+          regions1[i].flags != regions2[i].flags)
+        return FALSE;
+    }
+
+  if (decl1->junction_sides != decl2->junction_sides)
+    return FALSE;
+
+  return TRUE;
+}
+
+void
+gtk_css_node_declaration_add_to_widget_path (const GtkCssNodeDeclaration *decl,
+                                             GtkWidgetPath               *path,
+                                             guint                        pos)
+{
+  GQuark *classes;
+  GtkRegion *regions;
+  guint i;
+
+  /* Set widget regions */
+  regions = get_regions (decl);
+  for (i = 0; i < decl->n_regions; i++)
+    {
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+      gtk_widget_path_iter_add_region (path, pos,
+                                       g_quark_to_string (regions[i].class_quark),
+                                       regions[i].flags);
+G_GNUC_END_IGNORE_DEPRECATIONS
+    }
+
+  /* Set widget classes */
+  classes = get_classes (decl);
+  for (i = 0; i < decl->n_classes; i++)
+    {
+      gtk_widget_path_iter_add_class (path, pos,
+                                      g_quark_to_string (classes[i]));
+    }
+
+  /* Set widget state */
+  gtk_widget_path_iter_set_state (path, pos, decl->state);
+}
+
diff --git a/gtk/gtkcssnodedeclarationprivate.h b/gtk/gtkcssnodedeclarationprivate.h
new file mode 100644
index 0000000..767b6ec
--- /dev/null
+++ b/gtk/gtkcssnodedeclarationprivate.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2014 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_CSS_NODE_DECLARATION_PRIVATE_H__
+#define __GTK_CSS_NODE_DECLARATION_PRIVATE_H__
+
+#include "gtkenums.h"
+#include "gtkwidgetpath.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCssNodeDeclaration GtkCssNodeDeclaration;
+
+
+GtkCssNodeDeclaration * gtk_css_node_declaration_new                    (void);
+GtkCssNodeDeclaration * gtk_css_node_declaration_ref                    (GtkCssNodeDeclaration         
*decl);
+void                    gtk_css_node_declaration_unref                  (GtkCssNodeDeclaration         
*decl);
+
+gboolean                gtk_css_node_declaration_set_junction_sides     (GtkCssNodeDeclaration        **decl,
+                                                                         GtkJunctionSides               
junction_sides);
+GtkJunctionSides        gtk_css_node_declaration_get_junction_sides     (const GtkCssNodeDeclaration   
*decl);
+gboolean                gtk_css_node_declaration_set_state              (GtkCssNodeDeclaration        **decl,
+                                                                         GtkStateFlags                  
flags);
+GtkStateFlags           gtk_css_node_declaration_get_state              (const GtkCssNodeDeclaration   
*decl);
+
+gboolean                gtk_css_node_declaration_add_class              (GtkCssNodeDeclaration        **decl,
+                                                                         GQuark                         
class_quark);
+gboolean                gtk_css_node_declaration_remove_class           (GtkCssNodeDeclaration        **decl,
+                                                                         GQuark                         
class_quark);
+gboolean                gtk_css_node_declaration_has_class              (const GtkCssNodeDeclaration   *decl,
+                                                                         GQuark                         
class_quark);
+GList *                 gtk_css_node_declaration_list_classes           (const GtkCssNodeDeclaration   
*decl);
+
+gboolean                gtk_css_node_declaration_add_region             (GtkCssNodeDeclaration        **decl,
+                                                                         GQuark                         
region_quark,
+                                                                         GtkRegionFlags                 
flags);
+gboolean                gtk_css_node_declaration_remove_region          (GtkCssNodeDeclaration        **decl,
+                                                                         GQuark                         
region_quark);
+gboolean                gtk_css_node_declaration_has_region             (const GtkCssNodeDeclaration   *decl,
+                                                                         GQuark                         
region_quark,
+                                                                         GtkRegionFlags                
*flags_return);
+GList *                 gtk_css_node_declaration_list_regions           (const GtkCssNodeDeclaration   
*decl);
+
+guint                   gtk_css_node_declaration_hash                   (gconstpointer                  
elem);
+gboolean                gtk_css_node_declaration_equal                  (gconstpointer                  
elem1,
+                                                                         gconstpointer                  
elem2);
+
+void                    gtk_css_node_declaration_add_to_widget_path     (const GtkCssNodeDeclaration   *decl,
+                                                                         GtkWidgetPath                 *path,
+                                                                         guint                          pos);
+G_END_DECLS
+
+#endif /* __GTK_CSS_NODE_DECLARATION_PRIVATE_H__ */
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 97785f3..8ef33af 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -28,6 +28,7 @@
 #include "gtkcsscornervalueprivate.h"
 #include "gtkcssenumvalueprivate.h"
 #include "gtkcssimagevalueprivate.h"
+#include "gtkcssnodedeclarationprivate.h"
 #include "gtkcssnumbervalueprivate.h"
 #include "gtkcssrgbavalueprivate.h"
 #include "gtkcssshadowsvalueprivate.h"
@@ -129,15 +130,8 @@
 #define GTK_STYLE_CONTEXT_CACHED_CHANGE (GTK_CSS_CHANGE_STATE)
 
 typedef struct GtkStyleInfo GtkStyleInfo;
-typedef struct GtkRegion GtkRegion;
 typedef struct PropertyValue PropertyValue;
 
-struct GtkRegion
-{
-  GQuark class_quark;
-  GtkRegionFlags flags;
-};
-
 struct PropertyValue
 {
   GType       widget_type;
@@ -147,10 +141,7 @@ struct PropertyValue
 
 struct GtkStyleInfo
 {
-  GArray *style_classes;
-  GArray *regions;
-  GtkJunctionSides junction_sides;
-  GtkStateFlags state_flags;
+  GtkCssNodeDeclaration *decl;
   GtkCssComputedValues *values;
 };
 
@@ -306,8 +297,7 @@ style_info_new (void)
   GtkStyleInfo *info;
 
   info = g_slice_new0 (GtkStyleInfo);
-  info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
-  info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
+  info->decl = gtk_css_node_declaration_new ();
 
   return info;
 }
@@ -333,8 +323,7 @@ style_info_free (GtkStyleInfo *info)
 {
   if (info->values)
     g_object_unref (info->values);
-  g_array_free (info->style_classes, TRUE);
-  g_array_free (info->regions, TRUE);
+  gtk_css_node_declaration_unref (info->decl);
   g_slice_free (GtkStyleInfo, info);
 }
 
@@ -356,16 +345,7 @@ style_info_copy (GtkStyleInfo *info)
   GtkStyleInfo *copy;
 
   copy = style_info_new ();
-  g_array_insert_vals (copy->style_classes, 0,
-                       info->style_classes->data,
-                       info->style_classes->len);
-
-  g_array_insert_vals (copy->regions, 0,
-                       info->regions->data,
-                       info->regions->len);
-
-  copy->junction_sides = info->junction_sides;
-  copy->state_flags = info->state_flags;
+  copy->decl = gtk_css_node_declaration_ref (info->decl);
   style_info_set_values (copy, info->values);
 
   return copy;
@@ -374,28 +354,9 @@ style_info_copy (GtkStyleInfo *info)
 static guint
 style_info_hash (gconstpointer elem)
 {
-  const GtkStyleInfo *info;
-  guint i, hash = 0;
-
-  info = elem;
-
-  for (i = 0; i < info->style_classes->len; i++)
-    {
-      hash += g_array_index (info->style_classes, GQuark, i);
-      hash <<= 5;
-    }
+  const GtkStyleInfo *info = elem;
 
-  for (i = 0; i < info->regions->len; i++)
-    {
-      GtkRegion *region;
-
-      region = &g_array_index (info->regions, GtkRegion, i);
-      hash += region->class_quark;
-      hash += region->flags;
-      hash <<= 5;
-    }
-
-  return hash ^ info->state_flags;
+  return gtk_css_node_declaration_hash (info->decl);
 }
 
 static gboolean
@@ -407,29 +368,7 @@ style_info_equal (gconstpointer elem1,
   info1 = elem1;
   info2 = elem2;
 
-  if (info1->state_flags != info2->state_flags)
-    return FALSE;
-
-  if (info1->junction_sides != info2->junction_sides)
-    return FALSE;
-
-  if (info1->style_classes->len != info2->style_classes->len)
-    return FALSE;
-
-  if (memcmp (info1->style_classes->data,
-              info2->style_classes->data,
-              info1->style_classes->len * sizeof (GQuark)) != 0)
-    return FALSE;
-
-  if (info1->regions->len != info2->regions->len)
-    return FALSE;
-
-  if (memcmp (info1->regions->data,
-              info2->regions->data,
-              info1->regions->len * sizeof (GtkRegion)) != 0)
-    return FALSE;
-
-  return TRUE;
+  return gtk_css_node_declaration_equal (info1->decl, info2->decl);
 }
 
 static void
@@ -490,7 +429,7 @@ gtk_style_context_init (GtkStyleContext *style_context)
 
   /* Create default info store */
   priv->info = style_info_new ();
-  priv->info->state_flags = GTK_STATE_FLAG_DIR_LTR;
+  gtk_css_node_declaration_set_state (&priv->info->decl, GTK_STATE_FLAG_DIR_LTR);
 
   priv->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
 
@@ -717,40 +656,6 @@ gtk_style_context_is_saved (GtkStyleContext *context)
   return context->priv->saved_nodes != NULL;
 }
 
-static void
-style_info_add_to_widget_path (GtkStyleInfo  *info,
-                               GtkWidgetPath *path,
-                               guint          pos)
-{
-  guint i;
-
-  /* Set widget regions */
-  for (i = 0; i < info->regions->len; i++)
-    {
-      GtkRegion *region;
-
-      region = &g_array_index (info->regions, GtkRegion, i);
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-      gtk_widget_path_iter_add_region (path, pos,
-                                       g_quark_to_string (region->class_quark),
-                                       region->flags);
-G_GNUC_END_IGNORE_DEPRECATIONS
-    }
-
-  /* Set widget classes */
-  for (i = 0; i < info->style_classes->len; i++)
-    {
-      GQuark quark;
-
-      quark = g_array_index (info->style_classes, GQuark, i);
-      gtk_widget_path_iter_add_class (path, pos,
-                                      g_quark_to_string (quark));
-    }
-
-  /* Set widget state */
-  gtk_widget_path_iter_set_state (path, pos, info->state_flags);
-}
-
 static GtkWidgetPath *
 create_query_path (GtkStyleContext *context,
                    GtkStyleInfo    *info)
@@ -767,15 +672,15 @@ create_query_path (GtkStyleContext *context,
       GtkStyleInfo *root = g_slist_last (context->priv->saved_nodes)->data;
 
       if (length > 0)
-        style_info_add_to_widget_path (root, path, length - 1);
+        gtk_css_node_declaration_add_to_widget_path (root->decl, path, length - 1);
 
-      gtk_widget_path_append_type (path, length > 0 ?gtk_widget_path_iter_get_object_type (path, length - 1) 
: G_TYPE_NONE);
-      style_info_add_to_widget_path (info, path, length);
+      gtk_widget_path_append_type (path, length > 0 ? gtk_widget_path_iter_get_object_type (path, length - 
1) : G_TYPE_NONE);
+      gtk_css_node_declaration_add_to_widget_path (info->decl, path, length);
     }
   else
     {
       if (length > 0)
-        style_info_add_to_widget_path (info, path, length - 1);
+        gtk_css_node_declaration_add_to_widget_path (info->decl, path, length - 1);
     }
 
   return path;
@@ -856,7 +761,7 @@ style_values_lookup_for_state (GtkStyleContext *context,
 {
   GtkCssComputedValues *values;
 
-  if (context->priv->info->state_flags == state)
+  if (gtk_css_node_declaration_get_state (context->priv->info->decl) == state)
     return style_values_lookup (context);
 
   gtk_style_context_save (context);
@@ -1296,11 +1201,10 @@ gtk_style_context_set_state (GtkStyleContext *context,
   GtkStateFlags old_flags;
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
 
-  old_flags = context->priv->info->state_flags;
-  if (old_flags == flags)
-    return;
+  old_flags = gtk_css_node_declaration_get_state (context->priv->info->decl);
 
-  context->priv->info->state_flags = flags;
+  if (!gtk_css_node_declaration_set_state (&context->priv->info->decl, flags))
+    return;
 
   if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) &&
       !gtk_style_context_is_saved (context))
@@ -1324,7 +1228,7 @@ gtk_style_context_get_state (GtkStyleContext *context)
 {
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
 
-  return context->priv->info->state_flags;
+  return gtk_css_node_declaration_get_state (context->priv->info->decl);
 }
 
 /**
@@ -1583,98 +1487,6 @@ gtk_style_context_restore (GtkStyleContext *context)
   gtk_style_context_pop_style_info (context);
 }
 
-static gboolean
-style_class_find (GArray *array,
-                  GQuark  class_quark,
-                  guint  *position)
-{
-  gint min, max, mid;
-  gboolean found = FALSE;
-  guint pos;
-
-  if (position)
-    *position = 0;
-
-  if (!array || array->len == 0)
-    return FALSE;
-
-  min = 0;
-  max = array->len - 1;
-
-  do
-    {
-      GQuark item;
-
-      mid = (min + max) / 2;
-      item = g_array_index (array, GQuark, mid);
-
-      if (class_quark == item)
-        {
-          found = TRUE;
-          pos = mid;
-        }
-      else if (class_quark > item)
-        min = pos = mid + 1;
-      else
-        {
-          max = mid - 1;
-          pos = mid;
-        }
-    }
-  while (!found && min <= max);
-
-  if (position)
-    *position = pos;
-
-  return found;
-}
-
-static gboolean
-region_find (GArray *array,
-             GQuark  class_quark,
-             guint  *position)
-{
-  gint min, max, mid;
-  gboolean found = FALSE;
-  guint pos;
-
-  if (position)
-    *position = 0;
-
-  if (!array || array->len == 0)
-    return FALSE;
-
-  min = 0;
-  max = array->len - 1;
-
-  do
-    {
-      GtkRegion *region;
-
-      mid = (min + max) / 2;
-      region = &g_array_index (array, GtkRegion, mid);
-
-      if (region->class_quark == class_quark)
-        {
-          found = TRUE;
-          pos = mid;
-        }
-      else if (region->class_quark > class_quark)
-        min = pos = mid + 1;
-      else
-        {
-          max = mid - 1;
-          pos = mid;
-        }
-    }
-  while (!found && min <= max);
-
-  if (position)
-    *position = pos;
-
-  return found;
-}
-
 /**
  * gtk_style_context_add_class:
  * @context: a #GtkStyleContext
@@ -1704,9 +1516,7 @@ gtk_style_context_add_class (GtkStyleContext *context,
                              const gchar     *class_name)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
   GQuark class_quark;
-  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (class_name != NULL);
@@ -1714,14 +1524,8 @@ gtk_style_context_add_class (GtkStyleContext *context,
   priv = context->priv;
   class_quark = g_quark_from_string (class_name);
 
-  info = priv->info;
-
-  if (!style_class_find (info->style_classes, class_quark, &position))
-    {
-      g_array_insert_val (info->style_classes, position, class_quark);
-
-      gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
-    }
+  if (gtk_css_node_declaration_add_class (&priv->info->decl, class_quark))
+    gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
 }
 
 /**
@@ -1738,9 +1542,7 @@ gtk_style_context_remove_class (GtkStyleContext *context,
                                 const gchar     *class_name)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
   GQuark class_quark;
-  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (class_name != NULL);
@@ -1752,14 +1554,8 @@ gtk_style_context_remove_class (GtkStyleContext *context,
 
   priv = context->priv;
 
-  info = priv->info;
-
-  if (style_class_find (info->style_classes, class_quark, &position))
-    {
-      g_array_remove_index (info->style_classes, position);
-
-      gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
-    }
+  if (gtk_css_node_declaration_remove_class (&priv->info->decl, class_quark))
+    gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
 }
 
 /**
@@ -1779,7 +1575,6 @@ gtk_style_context_has_class (GtkStyleContext *context,
                              const gchar     *class_name)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
   GQuark class_quark;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
@@ -1792,12 +1587,18 @@ gtk_style_context_has_class (GtkStyleContext *context,
 
   priv = context->priv;
 
-  info = priv->info;
+  return gtk_css_node_declaration_has_class (priv->info->decl, class_quark);
+}
 
-  if (style_class_find (info->style_classes, class_quark, NULL))
-    return TRUE;
+static void
+quarks_to_strings (GList *list)
+{
+  GList *l;
 
-  return FALSE;
+  for (l = list; l; l = l->next)
+    {
+      l->data = (char *) g_quark_to_string (GPOINTER_TO_UINT (l->data));
+    }
 }
 
 /**
@@ -1817,23 +1618,14 @@ GList *
 gtk_style_context_list_classes (GtkStyleContext *context)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
-  GList *classes = NULL;
-  guint i;
+  GList *classes;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
 
   priv = context->priv;
-
-  info = priv->info;
-
-  for (i = 0; i < info->style_classes->len; i++)
-    {
-      GQuark quark;
-
-      quark = g_array_index (info->style_classes, GQuark, i);
-      classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
-    }
+  
+  classes = gtk_css_node_declaration_list_classes (priv->info->decl);
+  quarks_to_strings (classes);
 
   return classes;
 }
@@ -1857,28 +1649,16 @@ GList *
 gtk_style_context_list_regions (GtkStyleContext *context)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
-  GList *classes = NULL;
-  guint i;
+  GList *regions;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
 
   priv = context->priv;
 
-  info = priv->info;
-
-  for (i = 0; i < info->regions->len; i++)
-    {
-      GtkRegion *region;
-      const gchar *class_name;
-
-      region = &g_array_index (info->regions, GtkRegion, i);
+  regions = gtk_css_node_declaration_list_regions (priv->info->decl);
+  quarks_to_strings (regions);
 
-      class_name = g_quark_to_string (region->class_quark);
-      classes = g_list_prepend (classes, (gchar *) class_name);
-    }
-
-  return classes;
+  return regions;
 }
 
 gboolean
@@ -1940,9 +1720,7 @@ gtk_style_context_add_region (GtkStyleContext *context,
                               GtkRegionFlags   flags)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
   GQuark region_quark;
-  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (region_name != NULL);
@@ -1951,19 +1729,8 @@ gtk_style_context_add_region (GtkStyleContext *context,
   priv = context->priv;
   region_quark = g_quark_from_string (region_name);
 
-  info = priv->info;
-
-  if (!region_find (info->regions, region_quark, &position))
-    {
-      GtkRegion region;
-
-      region.class_quark = region_quark;
-      region.flags = flags;
-
-      g_array_insert_val (info->regions, position, region);
-
-      gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
-    }
+  if (gtk_css_node_declaration_add_region (&priv->info->decl, region_quark, flags))
+    gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
 }
 
 /**
@@ -1982,9 +1749,7 @@ gtk_style_context_remove_region (GtkStyleContext *context,
                                  const gchar     *region_name)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
   GQuark region_quark;
-  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (region_name != NULL);
@@ -1996,14 +1761,8 @@ gtk_style_context_remove_region (GtkStyleContext *context,
 
   priv = context->priv;
 
-  info = priv->info;
-
-  if (region_find (info->regions, region_quark, &position))
-    {
-      g_array_remove_index (info->regions, position);
-
-      gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
-    }
+  if (gtk_css_node_declaration_remove_region (&priv->info->decl, region_quark))
+    gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
 }
 
 /**
@@ -2028,9 +1787,7 @@ gtk_style_context_has_region (GtkStyleContext *context,
                               GtkRegionFlags  *flags_return)
 {
   GtkStyleContextPrivate *priv;
-  GtkStyleInfo *info;
   GQuark region_quark;
-  guint position;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
   g_return_val_if_fail (region_name != NULL, FALSE);
@@ -2045,21 +1802,7 @@ gtk_style_context_has_region (GtkStyleContext *context,
 
   priv = context->priv;
 
-  info = priv->info;
-
-  if (region_find (info->regions, region_quark, &position))
-    {
-      if (flags_return)
-        {
-          GtkRegion *region;
-
-          region = &g_array_index (info->regions, GtkRegion, position);
-          *flags_return = region->flags;
-        }
-      return TRUE;
-    }
-
-  return FALSE;
+  return gtk_css_node_declaration_has_region (priv->info->decl, region_quark, flags_return);
 }
 
 static gint
@@ -2629,7 +2372,7 @@ gtk_style_context_set_junction_sides (GtkStyleContext  *context,
 {
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
 
-  context->priv->info->junction_sides = sides;
+  gtk_css_node_declaration_set_junction_sides (&context->priv->info->decl, sides);
 }
 
 /**
@@ -2647,7 +2390,7 @@ gtk_style_context_get_junction_sides (GtkStyleContext *context)
 {
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
 
-  return context->priv->info->junction_sides;
+  return gtk_css_node_declaration_get_junction_sides (context->priv->info->decl);
 }
 
 gboolean
@@ -3854,6 +3597,7 @@ _gtk_style_context_get_icon_lookup_flags (GtkStyleContext *context)
 {
   GtkCssIconStyle icon_style;
   GtkIconLookupFlags flags;
+  GtkStateFlags state;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
 
@@ -3875,9 +3619,10 @@ _gtk_style_context_get_icon_lookup_flags (GtkStyleContext *context)
       return 0;
     }
 
-  if (context->priv->info->state_flags & GTK_STATE_FLAG_DIR_LTR)
+  state = gtk_style_context_get_state (context);
+  if (state & GTK_STATE_FLAG_DIR_LTR)
     flags |= GTK_ICON_LOOKUP_DIR_LTR;
-  else if (context->priv->info->state_flags & GTK_STATE_FLAG_DIR_RTL)
+  else if (state & GTK_STATE_FLAG_DIR_RTL)
     flags |= GTK_ICON_LOOKUP_DIR_RTL;
 
   return flags;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]