[gtk/wip/baedert/for-master: 19/29] cssprovider: Parse selectors without a GList



commit c2ba20b6557da1e78a16b3e50ab0e296b0094380
Author: Timm Bäder <mail baedert org>
Date:   Sat Jan 25 08:33:51 2020 +0100

    cssprovider: Parse selectors without a GList
    
    The maximum length of this list in Adwaita is 18, so use a generous
    maximum length of 64 for the selector list of a ruleset.

 gtk/gtkcssprovider.c | 58 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 22 deletions(-)
---
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 6c25afae67..d32328c034 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -74,6 +74,8 @@
  * way back to 4.0.
  */
 
+#define MAX_SELECTOR_LIST_LENGTH 64
+
 struct _GtkCssProviderClass
 {
   GObjectClass parent_class;
@@ -550,29 +552,28 @@ gtk_css_provider_new (void)
 }
 
 static void
-css_provider_commit (GtkCssProvider *css_provider,
-                     GSList         *selectors,
-                     GtkCssRuleset  *ruleset)
+css_provider_commit (GtkCssProvider  *css_provider,
+                     GtkCssSelector **selectors,
+                     guint            n_selectors,
+                     GtkCssRuleset   *ruleset)
 {
   GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (css_provider);
-  GSList *l;
+  guint i;
 
   if (ruleset->styles == NULL)
     {
-      g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
       return;
     }
 
-  for (l = selectors; l; l = l->next)
+  for (i = 0; i < n_selectors; i ++)
     {
-      GtkCssRuleset new;
+      GtkCssRuleset *new;
 
-      gtk_css_ruleset_init_copy (&new, ruleset, l->data);
+      g_array_set_size (priv->rulesets, priv->rulesets->len + 1);
 
-      g_array_append_val (priv->rulesets, new);
+      new = &g_array_index (priv->rulesets, GtkCssRuleset, priv->rulesets->len - 1);
+      gtk_css_ruleset_init_copy (new, ruleset, selectors[i]);
     }
-
-  g_slist_free (selectors);
 }
 
 static void
@@ -757,22 +758,32 @@ parse_at_keyword (GtkCssScanner *scanner)
   gtk_css_parser_end_block (scanner->parser);
 }
 
-static GSList *
-parse_selector_list (GtkCssScanner *scanner)
+static guint
+parse_selector_list (GtkCssScanner  *scanner,
+                     GtkCssSelector *out_selectors[MAX_SELECTOR_LIST_LENGTH])
 {
-  GSList *selectors = NULL;
+  guint n_selectors = 0;
 
   do {
       GtkCssSelector *select = _gtk_css_selector_parse (scanner->parser);
 
       if (select == NULL)
-        return NULL;
+        return 0;
+
+      out_selectors[n_selectors] = select;
+      n_selectors++;
 
-      selectors = g_slist_prepend (selectors, select);
+      if (G_UNLIKELY (n_selectors > MAX_SELECTOR_LIST_LENGTH))
+        {
+          gtk_css_parser_error_syntax (scanner->parser,
+                                       "Only %u selectors per ruleset allowed",
+                                       MAX_SELECTOR_LIST_LENGTH);
+          return 0;
+        }
     }
   while (gtk_css_parser_try_token (scanner->parser, GTK_CSS_TOKEN_COMMA));
 
-  return selectors;
+  return n_selectors;
 }
 
 static void
@@ -891,11 +902,12 @@ parse_declarations (GtkCssScanner *scanner,
 static void
 parse_ruleset (GtkCssScanner *scanner)
 {
-  GSList *selectors;
+  GtkCssSelector *selectors[MAX_SELECTOR_LIST_LENGTH];
+  guint n_selectors;
   GtkCssRuleset ruleset = { 0, };
 
-  selectors = parse_selector_list (scanner);
-  if (selectors == NULL)
+  n_selectors = parse_selector_list (scanner, selectors);
+  if (n_selectors == 0)
     {
       gtk_css_parser_skip_until (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY);
       gtk_css_parser_skip (scanner->parser);
@@ -904,8 +916,10 @@ parse_ruleset (GtkCssScanner *scanner)
 
   if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY))
     {
+      guint i;
       gtk_css_parser_error_syntax (scanner->parser, "Expected '{' after selectors");
-      g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
+      for (i = 0; i < n_selectors; i ++)
+        _gtk_css_selector_free (selectors[i]);
       gtk_css_parser_skip_until (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY);
       gtk_css_parser_skip (scanner->parser);
       return;
@@ -917,7 +931,7 @@ parse_ruleset (GtkCssScanner *scanner)
 
   gtk_css_parser_end_block (scanner->parser);
 
-  css_provider_commit (scanner->provider, selectors, &ruleset);
+  css_provider_commit (scanner->provider, selectors, n_selectors, &ruleset);
   gtk_css_ruleset_clear (&ruleset);
 }
 


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