[gtk+/wip/otte/tokenizer: 8/78] css: Add skeleton for new parsing infrastructure
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/tokenizer: 8/78] css: Add skeleton for new parsing infrastructure
- Date: Fri, 25 Nov 2016 22:32:22 +0000 (UTC)
commit 674ca8ae1cec4699a2bf5b8de8bc52889eb40e56
Author: Benjamin Otte <otte redhat com>
Date: Wed Mar 9 19:44:50 2016 +0100
css: Add skeleton for new parsing infrastructure
This infrastructure will be based around the CSSOM and return a
GtkCssStyleSheet object as its result.
The initial intended use for this is as a syntax tree while editing in
the inspector, but we might even want to look into exporting the CSSOM
parts as public API at some point.
gtk/Makefile.am | 12 +
gtk/gtkcssrule.c | 215 +++++++++++++
gtk/gtkcssrulelist.c | 166 ++++++++++
gtk/gtkcssrulelistprivate.h | 69 ++++
gtk/gtkcssruleprivate.h | 70 ++++
gtk/gtkcssselector.c | 597 +++++++++++++++++++++++++++++++++--
gtk/gtkcssselectorprivate.h | 2 +
gtk/gtkcssstyledeclaration.c | 66 ++++
gtk/gtkcssstyledeclarationprivate.h | 61 ++++
gtk/gtkcssstylerule.c | 124 ++++++++
gtk/gtkcssstyleruleprivate.h | 56 ++++
gtk/gtkcssstylesheet.c | 114 +++++++
gtk/gtkcssstylesheetprivate.h | 67 ++++
gtk/gtkcsstokensource.c | 369 +++++++++++++++++++++
gtk/gtkcsstokensourceprivate.h | 81 +++++
15 files changed, 2038 insertions(+), 31 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index a73ffa7..c7aba5c 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -434,6 +434,8 @@ gtk_private_h_sources = \
gtkcssrbtreeprivate.h \
gtkcssrepeatvalueprivate.h \
gtkcssrgbavalueprivate.h \
+ gtkcssruleprivate.h \
+ gtkcssrulelistprivate.h \
gtkcsssectionprivate.h \
gtkcssselectorprivate.h \
gtkcssshadowsvalueprivate.h \
@@ -445,7 +447,11 @@ gtk_private_h_sources = \
gtkcssstylechangeprivate.h \
gtkcssstyleprivate.h \
gtkcssstylepropertyprivate.h \
+ gtkcssstyledeclarationprivate.h \
+ gtkcssstyleruleprivate.h \
+ gtkcssstylesheetprivate.h \
gtkcsstokenizerprivate.h \
+ gtkcsstokensourceprivate.h \
gtkcsstransformvalueprivate.h \
gtkcsstransientnodeprivate.h \
gtkcsstransitionprivate.h \
@@ -704,11 +710,15 @@ gtk_base_c_sources = \
gtkcssrbtree.c \
gtkcssrepeatvalue.c \
gtkcssrgbavalue.c \
+ gtkcssrule.c \
+ gtkcssrulelist.c \
gtkcsssection.c \
gtkcssselector.c \
gtkcssstringvalue.c \
gtkcssstyle.c \
gtkcssstylechange.c \
+ gtkcssstyledeclaration.c \
+ gtkcssstylerule.c \
gtkcssshadowsvalue.c \
gtkcssshadowvalue.c \
gtkcssshorthandproperty.c \
@@ -717,7 +727,9 @@ gtk_base_c_sources = \
gtkcssstylefuncs.c \
gtkcssstyleproperty.c \
gtkcssstylepropertyimpl.c \
+ gtkcssstylesheet.c \
gtkcsstokenizer.c \
+ gtkcsstokensource.c \
gtkcsstransformvalue.c \
gtkcsstransientnode.c \
gtkcsstransition.c \
diff --git a/gtk/gtkcssrule.c b/gtk/gtkcssrule.c
new file mode 100644
index 0000000..d074a4a
--- /dev/null
+++ b/gtk/gtkcssrule.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssruleprivate.h"
+
+#include "gtkcssstylesheetprivate.h"
+
+typedef struct _GtkCssRulePrivate GtkCssRulePrivate;
+struct _GtkCssRulePrivate {
+ GtkCssRule *parent_rule;
+ GtkCssStyleSheet *parent_style_sheet;
+};
+
+typedef struct _GtkCssTokenSourceAt GtkCssTokenSourceAt;
+struct _GtkCssTokenSourceAt {
+ GtkCssTokenSource parent;
+ GtkCssTokenSource *source;
+ guint inside_curly_block :1;
+ guint done :1;
+};
+
+static void
+gtk_css_token_source_at_finalize (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
+
+ gtk_css_token_source_unref (at->source);
+}
+
+static void
+gtk_css_token_source_at_consume_token (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
+ const GtkCssToken *token;
+
+ if (at->done)
+ return;
+
+ if (gtk_css_token_get_pending_block (source))
+ {
+ gtk_css_token_source_consume_token (at->source);
+ return;
+ }
+
+ token = gtk_css_token_source_get_token (at->source);
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_SEMICOLON))
+ at->done = TRUE;
+ else if (at->inside_curly_block && gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_CURLY))
+ at->done = TRUE;
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_OPEN_CURLY))
+ at->inside_curly_block = TRUE;
+
+ gtk_css_token_source_consume_token (at->source);
+}
+
+const GtkCssToken *
+gtk_css_token_source_at_get_token (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
+ static GtkCssToken eof_token = { GTK_CSS_TOKEN_EOF };
+
+ if (at->done)
+ return &eof_token;
+
+ return gtk_css_token_source_get_token (at->source);
+}
+
+static void
+gtk_css_token_source_at_error (GtkCssTokenSource *source,
+ const GError *error)
+{
+ GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
+
+ gtk_css_token_source_emit_error (at->source, error);
+}
+
+static const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_AT = {
+ gtk_css_token_source_at_finalize,
+ gtk_css_token_source_at_consume_token,
+ gtk_css_token_source_at_get_token,
+ gtk_css_token_source_at_error
+};
+
+static GtkCssTokenSource *
+gtk_css_token_source_new_at (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceAt *at = gtk_css_token_source_new (GtkCssTokenSourceAt, >K_CSS_TOKEN_SOURCE_AT);
+
+ at->source = gtk_css_token_source_ref (source);
+
+ return &at->parent;
+}
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkCssRule, gtk_css_rule, G_TYPE_OBJECT)
+
+static void
+gtk_css_rule_class_init (GtkCssRuleClass *klass)
+{
+}
+
+static void
+gtk_css_rule_init (GtkCssRule *rule)
+{
+}
+
+GtkCssRule *
+gtk_css_rule_new_from_at_rule (GtkCssTokenSource *source,
+ GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet)
+{
+ GtkCssTokenSource *at_source;
+ const GtkCssToken *token;
+
+ g_return_val_if_fail (source != NULL, NULL);
+ g_return_val_if_fail (parent_rule == NULL || GTK_IS_CSS_RULE (parent_rule), NULL);
+ g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (parent_style_sheet), NULL);
+
+ at_source = gtk_css_token_source_new_at (source);
+
+ token = gtk_css_token_source_get_token (at_source);
+ if (token->type != GTK_CSS_TOKEN_AT_KEYWORD)
+ {
+ gtk_css_token_source_error (at_source, "Expected an '@'");
+ gtk_css_token_source_unref (at_source);
+ return NULL;
+ }
+ else
+ {
+ const char *name = token->string.string;
+
+ if (g_ascii_strcasecmp (name, "import") == 0)
+ {
+ gtk_css_token_source_error (source, "Add code to parse @import here");
+ }
+ else
+ {
+ gtk_css_token_source_unknown (source, "Unknown rule @%s", name);
+ }
+ }
+
+ gtk_css_token_source_consume_all (at_source);
+ gtk_css_token_source_unref (at_source);
+
+ return NULL;
+}
+
+void
+gtk_css_rule_print_css_text (GtkCssRule *rule,
+ GString *string)
+{
+ GtkCssRuleClass *klass;
+
+ g_return_if_fail (GTK_IS_CSS_RULE (rule));
+ g_return_if_fail (string != NULL);
+
+ klass = GTK_CSS_RULE_GET_CLASS (rule);
+
+ klass->get_css_text (rule, string);
+}
+
+char *
+gtk_css_rule_get_css_text (GtkCssRule *rule)
+{
+ GString *string;
+
+ g_return_val_if_fail (GTK_IS_CSS_RULE (rule), NULL);
+
+ string = g_string_new (NULL);
+
+ gtk_css_rule_print_css_text (rule, string);
+
+ return g_string_free (string, FALSE);
+}
+
+GtkCssRule *
+gtk_css_rule_get_parent_rule (GtkCssRule *rule)
+{
+ GtkCssRulePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_RULE (rule), NULL);
+
+ priv = gtk_css_rule_get_instance_private (rule);
+
+ return priv->parent_rule;
+}
+
+GtkCssStyleSheet *
+gtk_css_rule_get_parent_style_sheet (GtkCssRule *rule)
+{
+ GtkCssRulePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_RULE (rule), NULL);
+
+ priv = gtk_css_rule_get_instance_private (rule);
+
+ return priv->parent_style_sheet;
+}
diff --git a/gtk/gtkcssrulelist.c b/gtk/gtkcssrulelist.c
new file mode 100644
index 0000000..fa72a63
--- /dev/null
+++ b/gtk/gtkcssrulelist.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssrulelistprivate.h"
+#include "gtkcssstyleruleprivate.h"
+#include "gtkcssstylesheetprivate.h"
+
+typedef struct _GtkCssRuleListPrivate GtkCssRuleListPrivate;
+struct _GtkCssRuleListPrivate {
+ GPtrArray *items;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkCssRuleList, gtk_css_rule_list, G_TYPE_OBJECT)
+
+static void
+gtk_css_rule_list_finalize (GObject *object)
+{
+ GtkCssRuleList *rule_list = GTK_CSS_RULE_LIST (object);
+ GtkCssRuleListPrivate *priv = gtk_css_rule_list_get_instance_private (rule_list);
+
+ g_ptr_array_unref (priv->items);
+
+ G_OBJECT_CLASS (gtk_css_rule_list_parent_class)->finalize (object);
+}
+
+static void
+gtk_css_rule_list_class_init (GtkCssRuleListClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_css_rule_list_finalize;
+}
+
+static void
+gtk_css_rule_list_init (GtkCssRuleList *rule_list)
+{
+ GtkCssRuleListPrivate *priv = gtk_css_rule_list_get_instance_private (rule_list);
+
+ priv->items = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+GtkCssRuleList *
+gtk_css_rule_list_new (void)
+{
+ return g_object_new (GTK_TYPE_CSS_RULE_LIST, NULL);
+}
+
+void
+gtk_css_rule_list_parse (GtkCssRuleList *rule_list,
+ GtkCssTokenSource *source,
+ GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet)
+{
+ GtkCssRule *rule;
+ const GtkCssToken *token;
+
+ g_return_if_fail (GTK_IS_CSS_RULE_LIST (rule_list));
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (parent_rule == NULL || GTK_IS_CSS_RULE (parent_rule));
+ g_return_if_fail (GTK_IS_CSS_STYLE_SHEET (parent_style_sheet));
+
+ for (token = gtk_css_token_source_get_token (source);
+ token->type != GTK_CSS_TOKEN_EOF;
+ token = gtk_css_token_source_get_token (source))
+ {
+ switch (token->type)
+ {
+ case GTK_CSS_TOKEN_WHITESPACE:
+ gtk_css_token_source_consume_token (source);
+ break;
+
+ case GTK_CSS_TOKEN_AT_KEYWORD:
+ rule = gtk_css_rule_new_from_at_rule (source, parent_rule, parent_style_sheet);
+ if (rule)
+ gtk_css_rule_list_append (rule_list, rule);
+ break;
+
+ case GTK_CSS_TOKEN_CDO:
+ case GTK_CSS_TOKEN_CDC:
+ if (parent_rule == NULL)
+ {
+ gtk_css_token_source_consume_token (source);
+ break;
+ }
+ /* else fall through */
+ default:
+ rule = gtk_css_style_rule_new_parse (source, parent_rule, parent_style_sheet);
+ if (rule)
+ gtk_css_rule_list_append (rule_list, rule);
+ break;
+ }
+ }
+}
+
+void
+gtk_css_rule_list_insert (GtkCssRuleList *rule_list,
+ gsize id,
+ GtkCssRule *rule)
+{
+ GtkCssRuleListPrivate *priv;
+
+ g_return_if_fail (GTK_IS_CSS_RULE_LIST (rule_list));
+ g_return_if_fail (GTK_IS_CSS_RULE (rule));
+
+ priv = gtk_css_rule_list_get_instance_private (rule_list);
+
+ g_ptr_array_insert (priv->items, id, g_object_ref (rule));
+}
+
+void
+gtk_css_rule_list_append (GtkCssRuleList *rule_list,
+ GtkCssRule *rule)
+{
+ GtkCssRuleListPrivate *priv;
+
+ g_return_if_fail (GTK_IS_CSS_RULE_LIST (rule_list));
+ g_return_if_fail (GTK_IS_CSS_RULE (rule));
+
+ priv = gtk_css_rule_list_get_instance_private (rule_list);
+
+ g_ptr_array_add (priv->items, g_object_ref (rule));
+}
+
+GtkCssRule *
+gtk_css_rule_list_get_item (GtkCssRuleList *rule_list,
+ gsize id)
+{
+ GtkCssRuleListPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_RULE_LIST (rule_list), NULL);
+
+ priv = gtk_css_rule_list_get_instance_private (rule_list);
+ g_return_val_if_fail (id < priv->items->len, NULL);
+
+ return g_ptr_array_index (priv->items, id);
+}
+
+gsize
+gtk_css_rule_list_get_length (GtkCssRuleList *rule_list)
+{
+ GtkCssRuleListPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_RULE_LIST (rule_list), 0);
+
+ priv = gtk_css_rule_list_get_instance_private (rule_list);
+
+ return priv->items->len;
+}
diff --git a/gtk/gtkcssrulelistprivate.h b/gtk/gtkcssrulelistprivate.h
new file mode 100644
index 0000000..fb449fd
--- /dev/null
+++ b/gtk/gtkcssrulelistprivate.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_RULE_LIST_PRIVATE_H__
+#define __GTK_CSS_RULE_LIST_PRIVATE_H__
+
+#include "gtk/gtkcssruleprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_RULE_LIST (gtk_css_rule_list_get_type ())
+#define GTK_CSS_RULE_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_RULE_LIST,
GtkCssRuleList))
+#define GTK_CSS_RULE_LIST_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_RULE_LIST,
GtkCssRuleListClass))
+#define GTK_IS_CSS_RULE_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_RULE_LIST))
+#define GTK_IS_CSS_RULE_LIST_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_RULE_LIST))
+#define GTK_CSS_RULE_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_RULE_LIST,
GtkCssRuleListClass))
+
+typedef struct _GtkCssRuleList GtkCssRuleList;
+typedef struct _GtkCssRuleListClass GtkCssRuleListClass;
+
+struct _GtkCssRuleList
+{
+ GObject parent;
+};
+
+struct _GtkCssRuleListClass
+{
+ GObjectClass parent_class;
+};
+
+GType gtk_css_rule_list_get_type (void) G_GNUC_CONST;
+
+GtkCssRuleList * gtk_css_rule_list_new (void);
+
+void gtk_css_rule_list_parse (GtkCssRuleList *rule_list,
+ GtkCssTokenSource *source,
+ GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet);
+void gtk_css_rule_list_insert (GtkCssRuleList *rule_list,
+ gsize id,
+ GtkCssRule *rule);
+void gtk_css_rule_list_append (GtkCssRuleList *rule_list,
+ GtkCssRule *rule);
+
+/* GtkCSSRule DOM */
+GtkCssRule * gtk_css_rule_list_get_item (GtkCssRuleList *rule_list,
+ gsize id);
+gsize gtk_css_rule_list_get_length (GtkCssRuleList *rule_list);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_RULE_LIST_PRIVATE_H__ */
diff --git a/gtk/gtkcssruleprivate.h b/gtk/gtkcssruleprivate.h
new file mode 100644
index 0000000..6a07b60
--- /dev/null
+++ b/gtk/gtkcssruleprivate.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_RULE_PRIVATE_H__
+#define __GTK_CSS_RULE_PRIVATE_H__
+
+#include "gtk/gtkcsstokensourceprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_RULE (gtk_css_rule_get_type ())
+#define GTK_CSS_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_RULE, GtkCssRule))
+#define GTK_CSS_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_RULE, GtkCssRuleClass))
+#define GTK_IS_CSS_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_RULE))
+#define GTK_IS_CSS_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_RULE))
+#define GTK_CSS_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_RULE, GtkCssRuleClass))
+
+/* forward declaration */
+typedef struct _GtkCssStyleSheet GtkCssStyleSheet;
+
+typedef struct _GtkCssRule GtkCssRule;
+typedef struct _GtkCssRuleClass GtkCssRuleClass;
+
+struct _GtkCssRule
+{
+ GObject parent;
+};
+
+struct _GtkCssRuleClass
+{
+ GObjectClass parent_class;
+
+ /* gets the cssText for this rule */
+ void (* get_css_text) (GtkCssRule *rule,
+ GString *string);
+};
+
+GType gtk_css_rule_get_type (void) G_GNUC_CONST;
+
+GtkCssRule * gtk_css_rule_new_from_at_rule (GtkCssTokenSource *source,
+ GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet);
+
+void gtk_css_rule_print_css_text (GtkCssRule *rule,
+ GString *string);
+char * gtk_css_rule_get_css_text (GtkCssRule *rule);
+
+GtkCssRule * gtk_css_rule_get_parent_rule (GtkCssRule *rule);
+GtkCssStyleSheet * gtk_css_rule_get_parent_style_sheet (GtkCssRule *rule);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_RULE_PRIVATE_H__ */
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c
index 9309de5..c0f9ef0 100644
--- a/gtk/gtkcssselector.c
+++ b/gtk/gtkcssselector.c
@@ -25,6 +25,8 @@
#include "gtkcssprovider.h"
#include "gtkstylecontextprivate.h"
+#include <errno.h>
+#include <stdlib.h>
#if defined(_MSC_VER) && _MSC_VER >= 1500
# include <intrin.h>
#endif
@@ -1102,42 +1104,42 @@ parse_selector_pseudo_class_nth_child (GtkCssParser *parser,
return selector;
}
+static const struct {
+ const char *name;
+ gboolean deprecated;
+ GtkStateFlags state_flag;
+ PositionType position_type;
+ int position_a;
+ int position_b;
+} pseudo_classes[] = {
+ { "first-child", 0, 0, POSITION_FORWARD, 0, 1 },
+ { "last-child", 0, 0, POSITION_BACKWARD, 0, 1 },
+ { "only-child", 0, 0, POSITION_ONLY, 0, 0 },
+ { "sorted", 1, 0, POSITION_SORTED, 0, 0 },
+ { "active", 0, GTK_STATE_FLAG_ACTIVE, },
+ { "prelight", 1, GTK_STATE_FLAG_PRELIGHT, },
+ { "hover", 0, GTK_STATE_FLAG_PRELIGHT, },
+ { "selected", 0, GTK_STATE_FLAG_SELECTED, },
+ { "insensitive", 1, GTK_STATE_FLAG_INSENSITIVE, },
+ { "disabled", 0, GTK_STATE_FLAG_INSENSITIVE, },
+ { "inconsistent", 1, GTK_STATE_FLAG_INCONSISTENT, },
+ { "indeterminate", 0, GTK_STATE_FLAG_INCONSISTENT, },
+ { "focused", 1, GTK_STATE_FLAG_FOCUSED, },
+ { "focus", 0, GTK_STATE_FLAG_FOCUSED, },
+ { "backdrop", 0, GTK_STATE_FLAG_BACKDROP, },
+ { "dir(ltr)", 0, GTK_STATE_FLAG_DIR_LTR, },
+ { "dir(rtl)", 0, GTK_STATE_FLAG_DIR_RTL, },
+ { "link", 0, GTK_STATE_FLAG_LINK, },
+ { "visited", 0, GTK_STATE_FLAG_VISITED, },
+ { "checked", 0, GTK_STATE_FLAG_CHECKED, },
+ { "drop(active)", 0, GTK_STATE_FLAG_DROP_ACTIVE, }
+};
+
static GtkCssSelector *
parse_selector_pseudo_class (GtkCssParser *parser,
GtkCssSelector *selector,
gboolean negate)
{
- static const struct {
- const char *name;
- gboolean deprecated;
- GtkStateFlags state_flag;
- PositionType position_type;
- int position_a;
- int position_b;
- } pseudo_classes[] = {
- { "first-child", 0, 0, POSITION_FORWARD, 0, 1 },
- { "last-child", 0, 0, POSITION_BACKWARD, 0, 1 },
- { "only-child", 0, 0, POSITION_ONLY, 0, 0 },
- { "sorted", 1, 0, POSITION_SORTED, 0, 0 },
- { "active", 0, GTK_STATE_FLAG_ACTIVE, },
- { "prelight", 1, GTK_STATE_FLAG_PRELIGHT, },
- { "hover", 0, GTK_STATE_FLAG_PRELIGHT, },
- { "selected", 0, GTK_STATE_FLAG_SELECTED, },
- { "insensitive", 1, GTK_STATE_FLAG_INSENSITIVE, },
- { "disabled", 0, GTK_STATE_FLAG_INSENSITIVE, },
- { "inconsistent", 1, GTK_STATE_FLAG_INCONSISTENT, },
- { "indeterminate", 0, GTK_STATE_FLAG_INCONSISTENT, },
- { "focused", 1, GTK_STATE_FLAG_FOCUSED, },
- { "focus", 0, GTK_STATE_FLAG_FOCUSED, },
- { "backdrop", 0, GTK_STATE_FLAG_BACKDROP, },
- { "dir(ltr)", 0, GTK_STATE_FLAG_DIR_LTR, },
- { "dir(rtl)", 0, GTK_STATE_FLAG_DIR_RTL, },
- { "link", 0, GTK_STATE_FLAG_LINK, },
- { "visited", 0, GTK_STATE_FLAG_VISITED, },
- { "checked", 0, GTK_STATE_FLAG_CHECKED, },
- { "drop(active)", 0, GTK_STATE_FLAG_DROP_ACTIVE, }
-
- };
guint i;
if (_gtk_css_parser_try (parser, "nth-child", FALSE))
@@ -1305,6 +1307,539 @@ _gtk_css_selector_parse (GtkCssParser *parser)
return selector;
}
+GtkCssSelector *
+token_parse_selector_class (GtkCssTokenSource *source,
+ GtkCssSelector *selector,
+ gboolean negate)
+{
+ const GtkCssToken *token;
+
+ gtk_css_token_source_consume_token (source);
+ token = gtk_css_token_source_get_token (source);
+
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_CLASS
+ : >K_CSS_SELECTOR_CLASS,
+ selector);
+ selector->style_class.style_class = g_quark_from_string (token->string.string);
+ gtk_css_token_source_consume_token (source);
+ return selector;
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "No class name after '.' in selector");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+}
+
+static gboolean
+parse_plus_b (GtkCssTokenSource *source,
+ gboolean negate,
+ gint *b)
+{
+ const GtkCssToken *token;
+ gboolean has_seen_sign;
+
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+
+ if (negate)
+ {
+ has_seen_sign = TRUE;
+ }
+ else
+ {
+ if (gtk_css_token_is_delim (token, '+'))
+ {
+ gtk_css_token_source_consume_token (source);
+ gtk_css_token_source_consume_whitespace (source);
+ has_seen_sign = TRUE;
+ }
+ else if (gtk_css_token_is_delim (token, '-'))
+ {
+ gtk_css_token_source_consume_token (source);
+ gtk_css_token_source_consume_whitespace (source);
+ negate = TRUE;
+ has_seen_sign = TRUE;
+ }
+ }
+
+ token = gtk_css_token_source_get_token (source);
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER))
+ {
+ if (has_seen_sign && token->number.number >= 0)
+ {
+ *b = token->number.number;
+ if (negate)
+ *b = - *b;
+ return TRUE;
+ }
+ }
+
+ gtk_css_token_source_error (source, "Not a valid an+b type");
+ return FALSE;
+}
+
+gboolean
+parse_a_n_plus_b (GtkCssTokenSource *source,
+ gint *a,
+ gint *b)
+{
+ const GtkCssToken *token;
+
+ token = gtk_css_token_source_get_token (source);
+
+ if (gtk_css_token_is_ident (token, "even"))
+ {
+ *a = 2;
+ *b = 0;
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+ else if (gtk_css_token_is_ident (token, "odd"))
+ {
+ *a = 2;
+ *b = 1;
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER))
+ {
+ *a = 0;
+ *b = token->number.number;
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER_DIMENSION) &&
+ g_ascii_strcasecmp (token->dimension.dimension, "n") == 0)
+ {
+ *a = token->dimension.value;
+ gtk_css_token_source_consume_token (source);
+ return parse_plus_b (source, FALSE, b);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER_DIMENSION) &&
+ g_ascii_strcasecmp (token->dimension.dimension, "n-") == 0)
+ {
+ *a = token->dimension.value;
+ gtk_css_token_source_consume_token (source);
+ return parse_plus_b (source, TRUE, b);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER_DIMENSION) &&
+ g_ascii_strncasecmp (token->dimension.dimension, "n-", 2) == 0)
+ {
+ char *end;
+ *a = token->dimension.value;
+ errno = 0;
+ *b = strtoul (token->dimension.dimension + 2, &end, 10);
+ if (*end == '\0' && errno == 0)
+ {
+ gtk_css_token_source_consume_token (source);
+ return TRUE;
+ }
+ }
+ else if (gtk_css_token_is_ident (token, "-n"))
+ {
+ *a = -1;
+ gtk_css_token_source_consume_token (source);
+ return parse_plus_b (source, FALSE, b);
+ }
+ else if (gtk_css_token_is_ident (token, "-n-"))
+ {
+ *a = -1;
+ gtk_css_token_source_consume_token (source);
+ return parse_plus_b (source, TRUE, b);
+ }
+
+ gtk_css_token_source_error (source, "Not a valid an+b type");
+ return FALSE;
+}
+GtkCssSelector *
+token_parse_selector_pseudo_class (GtkCssTokenSource *source,
+ GtkCssSelector *selector,
+ gboolean negate)
+{
+ const GtkCssToken *token;
+
+ gtk_css_token_source_consume_token (source);
+ token = gtk_css_token_source_get_token (source);
+
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
+ {
+ if (g_ascii_strcasecmp (pseudo_classes[i].name, token->string.string) == 0)
+ {
+ if (pseudo_classes[i].state_flag)
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = pseudo_classes[i].state_flag;
+ if (pseudo_classes[i].deprecated)
+ {
+ if (pseudo_classes[i + 1].state_flag == pseudo_classes[i].state_flag)
+ gtk_css_token_source_deprecated (source,
+ "The :%s pseudo-class is deprecated. Use :%s
instead.",
+ pseudo_classes[i].name,
+ pseudo_classes[i + 1].name);
+ else
+ gtk_css_token_source_deprecated (source,
+ "The :%s pseudo-class is deprecated.",
+ pseudo_classes[i].name);
+ }
+ }
+ else
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
+ : >K_CSS_SELECTOR_PSEUDOCLASS_POSITION,
+ selector);
+ selector->position.type = pseudo_classes[i].position_type;
+ selector->position.a = pseudo_classes[i].position_a;
+ selector->position.b = pseudo_classes[i].position_b;
+ }
+ gtk_css_token_source_consume_token (source);
+ return selector;
+ }
+ }
+
+ gtk_css_token_source_unknown (source, "Unknown name of pseudo-class");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_FUNCTION))
+ {
+ gint a, b;
+
+ if (gtk_css_token_is_function (token, "nth-child"))
+ {
+ gtk_css_token_source_consume_token (source);
+ if (parse_a_n_plus_b (source, &a, &b))
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
+ : >K_CSS_SELECTOR_PSEUDOCLASS_POSITION,
+ selector);
+ selector->position.type = POSITION_FORWARD;
+ selector->position.a = a;
+ selector->position.b = b;
+ }
+ else
+ {
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
+ {
+ gtk_css_token_source_error (source, "Expected ')' at end of :nth-child()");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_function (token, "nth-last-child"))
+ {
+ gtk_css_token_source_consume_token (source);
+ if (parse_a_n_plus_b (source, &a, &b))
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
+ : >K_CSS_SELECTOR_PSEUDOCLASS_POSITION,
+ selector);
+ selector->position.type = POSITION_BACKWARD;
+ selector->position.a = a;
+ selector->position.b = b;
+ }
+ else
+ {
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
+ {
+ gtk_css_token_source_error (source, "Expected ')' at end of :nth-last-child()");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_function (token, "not"))
+ {
+ if (negate)
+ {
+ gtk_css_token_source_error (source, "Nesting of :not() not allowed");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ else
+ {
+ gtk_css_token_source_consume_token (source);
+ token = gtk_css_token_source_get_token (source);
+
+ if (gtk_css_token_is_delim (token, '*'))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_ANY, selector);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_NOT_NAME, selector);
+ selector->name.name = g_intern_string (token->string.string);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_NOT_ID, selector);
+ selector->id.name = g_intern_string (token->string.string);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_delim (token, '.'))
+ {
+ selector = token_parse_selector_class (source, selector, TRUE);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
+ {
+ selector = token_parse_selector_pseudo_class (source, selector, TRUE);
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Invalid contents of :not() selector");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ selector = NULL;
+ return NULL;
+ }
+
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
+ {
+ gtk_css_token_source_consume_token (source);
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Invalid contents of :not() selector");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ selector = NULL;
+ return NULL;
+ }
+ }
+ }
+ else if (gtk_css_token_is_function (token, "dir"))
+ {
+ gtk_css_token_source_consume_token (source);
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (gtk_css_token_is_ident (token, "ltr"))
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = GTK_STATE_FLAG_DIR_LTR;
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_ident (token, "rtl"))
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = GTK_STATE_FLAG_DIR_LTR;
+ gtk_css_token_source_consume_token (source);
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Expected :dir(ltr) or :dir(rtl)");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ selector = NULL;
+ return NULL;
+ }
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
+ {
+ gtk_css_token_source_error (source, "Expected ')' at end of :dir()");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_function (token, "drop"))
+ {
+ gtk_css_token_source_consume_token (source);
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (gtk_css_token_is_ident (token, "active"))
+ {
+ selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = GTK_STATE_FLAG_DROP_ACTIVE;
+ gtk_css_token_source_consume_token (source);
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Expected :drop(active)");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ selector = NULL;
+ return NULL;
+ }
+ gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
+ {
+ gtk_css_token_source_error (source, "Expected ')' at end of :drop()");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ gtk_css_token_source_consume_token (source);
+ }
+ else
+ {
+ gtk_css_token_source_unknown (source, "Unknown pseudoclass");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Unknown pseudoclass");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+
+ return selector;
+}
+
+GtkCssSelector *
+token_parse_simple_selector (GtkCssTokenSource *source,
+ GtkCssSelector *selector)
+{
+ gboolean parsed_something = FALSE;
+ const GtkCssToken *token;
+
+ do {
+ token = gtk_css_token_source_get_token (source);
+
+ if (!parsed_something && gtk_css_token_is_delim (token, '*'))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_ANY, selector);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (!parsed_something && gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_NAME, selector);
+ selector->name.name = g_intern_string (token->string.string);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_ID, selector);
+ selector->id.name = g_intern_string (token->string.string);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_delim (token, '.'))
+ {
+ selector = token_parse_selector_class (source, selector, FALSE);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
+ {
+ selector = token_parse_selector_pseudo_class (source, selector, FALSE);
+ }
+ else
+ {
+ if (!parsed_something)
+ {
+ gtk_css_token_source_error (source, "Expected a valid selector");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ selector = NULL;
+ }
+ break;
+ }
+
+ parsed_something = TRUE;
+ }
+ while (TRUE);
+
+ return selector;
+}
+
+GtkCssSelector *
+gtk_css_selector_token_parse (GtkCssTokenSource *source)
+{
+ GtkCssSelector *selector = NULL;
+ const GtkCssToken *token;
+
+ while (TRUE)
+ {
+ gboolean seen_whitespace = FALSE;
+
+ selector = token_parse_simple_selector (source, selector);
+ if (selector == NULL)
+ {
+ gtk_css_token_source_consume_all (source);
+ return NULL;
+ }
+
+ seen_whitespace = gtk_css_token_source_consume_whitespace (source);
+ token = gtk_css_token_source_get_token (source);
+
+ if (gtk_css_token_is_delim (token, '+'))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_ADJACENT, selector);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_delim (token, '~'))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_SIBLING, selector);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is_delim (token, '>'))
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_CHILD, selector);
+ gtk_css_token_source_consume_token (source);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
+ {
+ break;
+ }
+ else if (seen_whitespace)
+ {
+ selector = gtk_css_selector_new (>K_CSS_SELECTOR_DESCENDANT, selector);
+ }
+ else
+ {
+ gtk_css_token_source_error (source, "Expected a valid selector");
+ _gtk_css_selector_free (selector);
+ gtk_css_token_source_consume_all (source);
+ return NULL;
+ }
+
+ gtk_css_token_source_consume_whitespace (source);
+ }
+
+ return selector;
+}
+
void
_gtk_css_selector_free (GtkCssSelector *selector)
{
diff --git a/gtk/gtkcssselectorprivate.h b/gtk/gtkcssselectorprivate.h
index 64eb13d..55945ad 100644
--- a/gtk/gtkcssselectorprivate.h
+++ b/gtk/gtkcssselectorprivate.h
@@ -20,6 +20,7 @@
#include "gtk/gtkcssmatcherprivate.h"
#include "gtk/gtkcssparserprivate.h"
+#include "gtk/gtkcsstokensourceprivate.h"
G_BEGIN_DECLS
@@ -28,6 +29,7 @@ typedef struct _GtkCssSelectorTree GtkCssSelectorTree;
typedef struct _GtkCssSelectorTreeBuilder GtkCssSelectorTreeBuilder;
GtkCssSelector * _gtk_css_selector_parse (GtkCssParser *parser);
+GtkCssSelector * gtk_css_selector_token_parse (GtkCssTokenSource *parser);
void _gtk_css_selector_free (GtkCssSelector *selector);
char * _gtk_css_selector_to_string (const GtkCssSelector *selector);
diff --git a/gtk/gtkcssstyledeclaration.c b/gtk/gtkcssstyledeclaration.c
new file mode 100644
index 0000000..a543a2c
--- /dev/null
+++ b/gtk/gtkcssstyledeclaration.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssstyledeclarationprivate.h"
+
+#include "gtkcssselectorprivate.h"
+#include "gtkcssstylesheetprivate.h"
+
+typedef struct _GtkCssStyleDeclarationPrivate GtkCssStyleDeclarationPrivate;
+struct _GtkCssStyleDeclarationPrivate {
+ GPtrArray *declarations;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkCssStyleDeclaration, gtk_css_style_declaration, G_TYPE_OBJECT)
+
+static void
+gtk_css_style_declaration_finalize (GObject *object)
+{
+ GtkCssStyleDeclaration *style_declaration = GTK_CSS_STYLE_DECLARATION (object);
+ GtkCssStyleDeclarationPrivate *priv = gtk_css_style_declaration_get_instance_private (style_declaration);
+
+ g_ptr_array_unref (priv->declarations);
+
+ G_OBJECT_CLASS (gtk_css_style_declaration_parent_class)->finalize (object);
+}
+
+static void
+gtk_css_style_declaration_class_init (GtkCssStyleDeclarationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_css_style_declaration_finalize;
+}
+
+static void
+gtk_css_style_declaration_init (GtkCssStyleDeclaration *style_declaration)
+{
+ GtkCssStyleDeclarationPrivate *priv = gtk_css_style_declaration_get_instance_private (style_declaration);
+
+ priv->declarations = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+GtkCssStyleDeclaration *
+gtk_css_style_declaration_new (GtkCssRule *parent_rule)
+{
+ return g_object_new (GTK_TYPE_CSS_STYLE_DECLARATION, NULL);
+}
+
diff --git a/gtk/gtkcssstyledeclarationprivate.h b/gtk/gtkcssstyledeclarationprivate.h
new file mode 100644
index 0000000..14ca8e0
--- /dev/null
+++ b/gtk/gtkcssstyledeclarationprivate.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_STYLE_DECLARATION_PRIVATE_H__
+#define __GTK_CSS_STYLE_DECLARATION_PRIVATE_H__
+
+#include "gtk/gtkcssruleprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_STYLE_DECLARATION (gtk_css_style_declaration_get_type ())
+#define GTK_CSS_STYLE_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj,
GTK_TYPE_CSS_STYLE_DECLARATION, GtkCssStyleDeclaration))
+#define GTK_CSS_STYLE_DECLARATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls,
GTK_TYPE_CSS_STYLE_DECLARATION, GtkCssStyleDeclarationClass))
+#define GTK_IS_CSS_STYLE_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj,
GTK_TYPE_CSS_STYLE_DECLARATION))
+#define GTK_IS_CSS_STYLE_DECLARATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj,
GTK_TYPE_CSS_STYLE_DECLARATION))
+#define GTK_CSS_STYLE_DECLARATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTK_TYPE_CSS_STYLE_DECLARATION, GtkCssStyleDeclarationClass))
+
+typedef struct _GtkCssStyleDeclaration GtkCssStyleDeclaration;
+typedef struct _GtkCssStyleDeclarationClass GtkCssStyleDeclarationClass;
+
+struct _GtkCssStyleDeclaration
+{
+ GObject parent;
+};
+
+struct _GtkCssStyleDeclarationClass
+{
+ GObjectClass parent_class;
+};
+
+GType gtk_css_style_declaration_get_type (void) G_GNUC_CONST;
+
+GtkCssStyleDeclaration *gtk_css_style_declaration_new (GtkCssRule
*parent_rule);
+
+void gtk_css_style_declaration_print_css_text (GtkCssStyleDeclaration *declaration,
+ GString *string);
+char * gtk_css_style_declaration_get_css_text (GtkCssStyleDeclaration
*declaration);
+
+/* GtkCssStyleDeclaration DOM */
+gsize gtk_css_style_declaration_get_length (GtkCssStyleDeclaration
*declaration);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_STYLE_DECLARATION_PRIVATE_H__ */
diff --git a/gtk/gtkcssstylerule.c b/gtk/gtkcssstylerule.c
new file mode 100644
index 0000000..74df7fa
--- /dev/null
+++ b/gtk/gtkcssstylerule.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssstyleruleprivate.h"
+
+#include "gtkcssselectorprivate.h"
+#include "gtkcssstylesheetprivate.h"
+
+typedef struct _GtkCssStyleRulePrivate GtkCssStyleRulePrivate;
+struct _GtkCssStyleRulePrivate {
+ GPtrArray *selectors;
+ //GtkCssStyleDeclaration *declaration;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkCssStyleRule, gtk_css_style_rule, GTK_TYPE_CSS_RULE)
+
+static void
+gtk_css_style_rule_finalize (GObject *object)
+{
+ GtkCssStyleRule *style_rule = GTK_CSS_STYLE_RULE (object);
+ GtkCssStyleRulePrivate *priv = gtk_css_style_rule_get_instance_private (style_rule);
+
+ g_ptr_array_unref (priv->selectors);
+
+ G_OBJECT_CLASS (gtk_css_style_rule_parent_class)->finalize (object);
+}
+
+static void
+gtk_css_style_rule_class_init (GtkCssStyleRuleClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_css_style_rule_finalize;
+}
+
+static void
+gtk_css_style_rule_init (GtkCssStyleRule *style_rule)
+{
+ GtkCssStyleRulePrivate *priv = gtk_css_style_rule_get_instance_private (style_rule);
+
+ priv->selectors = g_ptr_array_new_with_free_func ((GDestroyNotify) _gtk_css_selector_free);
+}
+
+static GtkCssRule *
+gtk_css_style_rule_new (GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet)
+{
+ return g_object_new (GTK_TYPE_CSS_STYLE_RULE, NULL);
+}
+
+static GtkCssStyleRule *
+gtk_css_style_rule_parse_selectors (GtkCssStyleRule *rule,
+ GtkCssTokenSource *source)
+{
+ GtkCssStyleRulePrivate *priv = gtk_css_style_rule_get_instance_private (rule);
+ GtkCssTokenSource *child_source;
+ GtkCssSelector *selector;
+ const GtkCssToken *token;
+
+ for (token = gtk_css_token_source_get_token (source);
+ !gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
+ token = gtk_css_token_source_get_token (source))
+ {
+ gtk_css_token_source_consume_whitespace (source);
+ child_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_COMMA);
+ selector = gtk_css_selector_token_parse (child_source);
+ gtk_css_token_source_unref (child_source);
+ if (selector == NULL)
+ {
+ g_object_unref (rule);
+ return NULL;
+ }
+ g_ptr_array_add (priv->selectors, selector);
+ gtk_css_token_source_consume_token (source);
+ }
+
+ return rule;
+}
+
+GtkCssRule *
+gtk_css_style_rule_new_parse (GtkCssTokenSource *source,
+ GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet)
+{
+ GtkCssTokenSource *child_source;
+ GtkCssStyleRule *rule;
+
+ g_return_val_if_fail (source != NULL, NULL);
+ g_return_val_if_fail (parent_rule == NULL || GTK_IS_CSS_RULE (parent_rule), NULL);
+ g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (parent_style_sheet), NULL);
+
+ rule = GTK_CSS_STYLE_RULE (gtk_css_style_rule_new (parent_rule, parent_style_sheet));
+
+ child_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_OPEN_CURLY);
+ rule = gtk_css_style_rule_parse_selectors (rule, child_source);
+ gtk_css_token_source_unref (child_source);
+
+ gtk_css_token_source_consume_token (source);
+ child_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_CLOSE_CURLY);
+ gtk_css_token_source_consume_all (child_source);
+ gtk_css_token_source_unref (child_source);
+ gtk_css_token_source_consume_token (source);
+
+ return GTK_CSS_RULE (rule);
+}
+
diff --git a/gtk/gtkcssstyleruleprivate.h b/gtk/gtkcssstyleruleprivate.h
new file mode 100644
index 0000000..ef5b936
--- /dev/null
+++ b/gtk/gtkcssstyleruleprivate.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_STYLE_RULE_PRIVATE_H__
+#define __GTK_CSS_STYLE_RULE_PRIVATE_H__
+
+#include "gtk/gtkcssruleprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_STYLE_RULE (gtk_css_style_rule_get_type ())
+#define GTK_CSS_STYLE_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_STYLE_RULE,
GtkCssStyleRule))
+#define GTK_CSS_STYLE_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_STYLE_RULE,
GtkCssStyleRuleClass))
+#define GTK_IS_CSS_STYLE_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_STYLE_RULE))
+#define GTK_IS_CSS_STYLE_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_STYLE_RULE))
+#define GTK_CSS_STYLE_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_STYLE_RULE,
GtkCssStyleRuleClass))
+
+typedef struct _GtkCssStyleRule GtkCssStyleRule;
+typedef struct _GtkCssStyleRuleClass GtkCssStyleRuleClass;
+
+struct _GtkCssStyleRule
+{
+ GtkCssRule parent;
+};
+
+struct _GtkCssStyleRuleClass
+{
+ GtkCssRuleClass parent_class;
+};
+
+GType gtk_css_style_rule_get_type (void) G_GNUC_CONST;
+
+GtkCssRule * gtk_css_style_rule_new_parse (GtkCssTokenSource *source,
+ GtkCssRule *parent_rule,
+ GtkCssStyleSheet *parent_style_sheet);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_STYLE_RULE_PRIVATE_H__ */
diff --git a/gtk/gtkcssstylesheet.c b/gtk/gtkcssstylesheet.c
new file mode 100644
index 0000000..03a027b
--- /dev/null
+++ b/gtk/gtkcssstylesheet.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssstylesheetprivate.h"
+
+typedef struct _GtkCssStyleSheetPrivate GtkCssStyleSheetPrivate;
+struct _GtkCssStyleSheetPrivate {
+ GtkCssRule *parent_rule;
+ GtkCssRuleList *css_rules;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkCssStyleSheet, gtk_css_style_sheet, G_TYPE_OBJECT)
+
+static void
+gtk_css_style_sheet_finalize (GObject *object)
+{
+ GtkCssStyleSheet *style_sheet = GTK_CSS_STYLE_SHEET (object);
+ GtkCssStyleSheetPrivate *priv = gtk_css_style_sheet_get_instance_private (style_sheet);
+
+ g_object_unref (priv->css_rules);
+
+ G_OBJECT_CLASS (gtk_css_style_sheet_parent_class)->finalize (object);
+}
+
+static void
+gtk_css_style_sheet_class_init (GtkCssStyleSheetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_css_style_sheet_finalize;
+}
+
+static void
+gtk_css_style_sheet_init (GtkCssStyleSheet *style_sheet)
+{
+ GtkCssStyleSheetPrivate *priv = gtk_css_style_sheet_get_instance_private (style_sheet);
+
+ priv->css_rules = gtk_css_rule_list_new ();
+}
+
+GtkCssStyleSheet *
+gtk_css_style_sheet_new (void)
+{
+ return g_object_new (GTK_TYPE_CSS_STYLE_SHEET, NULL);
+}
+
+void
+gtk_css_style_sheet_parse (GtkCssStyleSheet *style_sheet,
+ GtkCssTokenSource *source)
+{
+ GtkCssStyleSheetPrivate *priv;
+
+ g_return_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet));
+ g_return_if_fail (source != NULL);
+
+ priv = gtk_css_style_sheet_get_instance_private (style_sheet);
+
+ gtk_css_rule_list_parse (priv->css_rules, source, NULL, style_sheet);
+}
+
+GtkCssStyleSheet *
+gtk_css_style_sheet_get_parent_style_sheet (GtkCssStyleSheet *style_sheet)
+{
+ GtkCssStyleSheetPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
+
+ priv = gtk_css_style_sheet_get_instance_private (style_sheet);
+
+ return gtk_css_rule_get_parent_style_sheet (priv->parent_rule);
+}
+
+GtkCssRule *
+gtk_css_style_sheet_get_parent_rule (GtkCssStyleSheet *style_sheet)
+{
+ GtkCssStyleSheetPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
+
+ priv = gtk_css_style_sheet_get_instance_private (style_sheet);
+
+ return priv->parent_rule;
+}
+
+GtkCssRuleList *
+gtk_css_style_sheet_get_css_rules (GtkCssStyleSheet *style_sheet)
+{
+ GtkCssStyleSheetPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
+
+ priv = gtk_css_style_sheet_get_instance_private (style_sheet);
+
+ return priv->css_rules;
+}
+
diff --git a/gtk/gtkcssstylesheetprivate.h b/gtk/gtkcssstylesheetprivate.h
new file mode 100644
index 0000000..f2d9132
--- /dev/null
+++ b/gtk/gtkcssstylesheetprivate.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_STYLE_SHEET_PRIVATE_H__
+#define __GTK_CSS_STYLE_SHEET_PRIVATE_H__
+
+#include "gtk/gtkcssruleprivate.h"
+#include "gtk/gtkcssrulelistprivate.h"
+#include "gtk/gtkcsstokensourceprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_STYLE_SHEET (gtk_css_style_sheet_get_type ())
+#define GTK_CSS_STYLE_SHEET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_STYLE_SHEET,
GtkCssStyleSheet))
+#define GTK_CSS_STYLE_SHEET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_STYLE_SHEET,
GtkCssStyleSheetClass))
+#define GTK_IS_CSS_STYLE_SHEET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_STYLE_SHEET))
+#define GTK_IS_CSS_STYLE_SHEET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_STYLE_SHEET))
+#define GTK_CSS_STYLE_SHEET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_STYLE_SHEET,
GtkCssStyleSheetClass))
+
+/* declared with GtkCssRule */
+/* typedef struct _GtkCssStyleSheet GtkCssStyleSheet; */
+typedef struct _GtkCssStyleSheetClass GtkCssStyleSheetClass;
+
+struct _GtkCssStyleSheet
+{
+ GObject parent;
+};
+
+struct _GtkCssStyleSheetClass
+{
+ GObjectClass parent_class;
+};
+
+GType gtk_css_style_sheet_get_type (void) G_GNUC_CONST;
+
+GtkCssStyleSheet * gtk_css_style_sheet_new (void);
+
+void gtk_css_style_sheet_parse (GtkCssStyleSheet *style_sheet,
+ GtkCssTokenSource *source);
+
+/* StyleSheet interface */
+GtkCssStyleSheet * gtk_css_style_sheet_get_parent_style_sheet (GtkCssStyleSheet
*style_sheet);
+
+/* CSSStyleSheet interface */
+GtkCssRule * gtk_css_style_sheet_get_parent_rule (GtkCssStyleSheet
*style_sheet);
+GtkCssRuleList * gtk_css_style_sheet_get_css_rules (GtkCssStyleSheet
*style_sheet);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_STYLE_SHEET_PRIVATE_H__ */
diff --git a/gtk/gtkcsstokensource.c b/gtk/gtkcsstokensource.c
new file mode 100644
index 0000000..069cf9b
--- /dev/null
+++ b/gtk/gtkcsstokensource.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcsstokensourceprivate.h"
+
+#include "gtkcssprovider.h"
+
+typedef struct _GtkCssTokenSourceTokenizer GtkCssTokenSourceTokenizer;
+struct _GtkCssTokenSourceTokenizer {
+ GtkCssTokenSource parent;
+ GtkCssTokenizer *tokenizer;
+ GtkCssToken current_token;
+};
+
+static void
+gtk_css_token_source_tokenizer_finalize (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
+
+ gtk_css_token_clear (&tok->current_token);
+ gtk_css_tokenizer_unref (tok->tokenizer);
+}
+
+static void
+gtk_css_token_source_tokenizer_consume_token (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
+
+ gtk_css_token_clear (&tok->current_token);
+}
+
+static const GtkCssToken *
+gtk_css_token_source_tokenizer_get_token (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
+
+ if (gtk_css_token_is (&tok->current_token, GTK_CSS_TOKEN_EOF))
+ {
+ do {
+ gtk_css_tokenizer_read_token (tok->tokenizer, &tok->current_token);
+ } while (gtk_css_token_is (&tok->current_token, GTK_CSS_TOKEN_COMMENT));
+
+#if 0
+ if (!gtk_css_token_is (&tok->current_token, GTK_CSS_TOKEN_EOF)) {
+ char *s = gtk_css_token_to_string (&tok->current_token);
+ g_print ("%3zu:%02zu %2d %s\n",
+ gtk_css_tokenizer_get_line (tok->tokenizer), gtk_css_tokenizer_get_line_char
(tok->tokenizer),
+ tok->current_token.type, s);
+ g_free (s);
+ }
+#endif
+ }
+
+ return &tok->current_token;
+}
+
+static void
+gtk_css_token_source_tokenizer_error (GtkCssTokenSource *source,
+ const GError *error)
+{
+ GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
+
+ /* XXX */
+ g_print ("ERROR: %zu:%zu: %s\n",
+ gtk_css_tokenizer_get_line (tok->tokenizer),
+ gtk_css_tokenizer_get_line_char (tok->tokenizer),
+ error->message);
+}
+
+const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_TOKENIZER = {
+ gtk_css_token_source_tokenizer_finalize,
+ gtk_css_token_source_tokenizer_consume_token,
+ gtk_css_token_source_tokenizer_get_token,
+ gtk_css_token_source_tokenizer_error,
+};
+
+GtkCssTokenSource *
+gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer)
+{
+ GtkCssTokenSourceTokenizer *source;
+
+ g_return_val_if_fail (tokenizer != NULL, NULL);
+
+ source = gtk_css_token_source_new (GtkCssTokenSourceTokenizer, >K_CSS_TOKEN_SOURCE_TOKENIZER);
+ source->tokenizer = gtk_css_tokenizer_ref (tokenizer);
+
+ return &source->parent;
+}
+
+typedef struct _GtkCssTokenSourcePart GtkCssTokenSourcePart;
+struct _GtkCssTokenSourcePart {
+ GtkCssTokenSource parent;
+ GtkCssTokenSource *source;
+ GtkCssTokenType end_type;
+};
+
+static void
+gtk_css_token_source_part_finalize (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
+
+ gtk_css_token_source_unref (part->source);
+}
+
+static void
+gtk_css_token_source_part_consume_token (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
+ const GtkCssToken *token;
+
+ if (!gtk_css_token_get_pending_block (source))
+ {
+ token = gtk_css_token_source_get_token (part->source);
+ if (gtk_css_token_is (token, part->end_type))
+ return;
+ }
+
+ gtk_css_token_source_consume_token (part->source);
+}
+
+static const GtkCssToken *
+gtk_css_token_source_part_get_token (GtkCssTokenSource *source)
+{
+ GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
+ static const GtkCssToken eof_token = { GTK_CSS_TOKEN_EOF };
+ const GtkCssToken *token;
+
+ token = gtk_css_token_source_get_token (part->source);
+ if (!gtk_css_token_get_pending_block (source) &&
+ gtk_css_token_is (token, part->end_type))
+ return &eof_token;
+
+ return token;
+}
+
+static void
+gtk_css_token_source_part_error (GtkCssTokenSource *source,
+ const GError *error)
+{
+ GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
+
+ gtk_css_token_source_emit_error (part->source, error);
+}
+
+const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_PART = {
+ gtk_css_token_source_part_finalize,
+ gtk_css_token_source_part_consume_token,
+ gtk_css_token_source_part_get_token,
+ gtk_css_token_source_part_error,
+};
+
+GtkCssTokenSource *
+gtk_css_token_source_new_for_part (GtkCssTokenSource *source,
+ GtkCssTokenType end_type)
+{
+ GtkCssTokenSourcePart *part;
+
+ g_return_val_if_fail (source != NULL, NULL);
+ g_return_val_if_fail (end_type != GTK_CSS_TOKEN_EOF, NULL);
+
+ part = gtk_css_token_source_new (GtkCssTokenSourcePart, >K_CSS_TOKEN_SOURCE_PART);
+ part->source = gtk_css_token_source_ref (source);
+ part->end_type = end_type;
+
+ return &part->parent;
+}
+
+GtkCssTokenSource *
+gtk_css_token_source_alloc (gsize struct_size,
+ const GtkCssTokenSourceClass *klass)
+{
+ GtkCssTokenSource *source;
+
+ source = g_malloc0 (struct_size);
+ source->klass = klass;
+ source->ref_count = 1;
+
+ return source;
+}
+
+GtkCssTokenSource *
+gtk_css_token_source_ref (GtkCssTokenSource *source)
+{
+ source->ref_count++;
+
+ return source;
+}
+
+void
+gtk_css_token_source_unref (GtkCssTokenSource *source)
+{
+ source->ref_count--;
+ if (source->ref_count > 0)
+ return;
+
+ source->klass->finalize (source);
+
+ g_free (source);
+}
+
+
+void
+gtk_css_token_source_consume_token (GtkCssTokenSource *source)
+{
+ gtk_css_token_source_consume_token_as (source, source->consumer);
+}
+
+void
+gtk_css_token_source_consume_token_as (GtkCssTokenSource *source,
+ GObject *consumer)
+{
+ const GtkCssToken *token;
+
+ if (source->blocks)
+ {
+ token = gtk_css_token_source_get_token (source);
+ if (gtk_css_token_is (token, GPOINTER_TO_UINT (source->blocks->data)))
+ source->blocks = g_slist_remove (source->blocks, source->blocks->data);
+ }
+
+ source->klass->consume_token (source);
+
+ token = gtk_css_token_source_get_token (source);
+ switch (token->type)
+ {
+ case GTK_CSS_TOKEN_FUNCTION:
+ case GTK_CSS_TOKEN_OPEN_PARENS:
+ source->blocks = g_slist_prepend (source->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_PARENS));
+ break;
+ case GTK_CSS_TOKEN_OPEN_SQUARE:
+ source->blocks = g_slist_prepend (source->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_SQUARE));
+ break;
+ case GTK_CSS_TOKEN_OPEN_CURLY:
+ source->blocks = g_slist_prepend (source->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_CURLY));
+ break;
+ default:
+ break;
+ }
+
+ source->klass->consume_token (source, consumer);
+
+ if (source->blocks)
+ {
+ if (token_type == GPOINTER_TO_UINT (source->blocks->data))
+ source->blocks = g_slist_remove (source->blocks, source->blocks->data);
+ }
+}
+
+const GtkCssToken *
+gtk_css_token_source_get_token (GtkCssTokenSource *source)
+{
+ return source->klass->get_token (source);
+}
+
+void
+gtk_css_token_source_consume_all (GtkCssTokenSource *source)
+{
+ const GtkCssToken *token;
+
+ for (token = gtk_css_token_source_get_token (source);
+ !gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
+ token = gtk_css_token_source_get_token (source))
+ {
+ gtk_css_token_source_consume_token (source);
+ }
+}
+
+gboolean
+gtk_css_token_source_consume_whitespace (GtkCssTokenSource *source)
+{
+ const GtkCssToken *token;
+ gboolean seen_whitespace = FALSE;
+
+ for (token = gtk_css_token_source_get_token (source);
+ gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
+ token = gtk_css_token_source_get_token (source))
+ {
+ seen_whitespace = TRUE;
+ gtk_css_token_source_consume_token (source);
+ }
+
+ return seen_whitespace;
+}
+
+GtkCssTokenType
+gtk_css_token_get_pending_block (GtkCssTokenSource *source)
+{
+ if (!source->blocks)
+ return GTK_CSS_TOKEN_EOF;
+
+ return GPOINTER_TO_UINT(source->blocks->data);
+}
+
+void
+gtk_css_token_source_emit_error (GtkCssTokenSource *source,
+ const GError *error)
+{
+ source->klass->error (source, error);
+}
+
+void
+gtk_css_token_source_error (GtkCssTokenSource *source,
+ const char *format,
+ ...)
+{
+ va_list args;
+ GError *error;
+
+ va_start (args, format);
+ error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_SYNTAX,
+ format, args);
+ gtk_css_token_source_emit_error (source, error);
+ g_error_free (error);
+ va_end (args);
+}
+
+void
+gtk_css_token_source_unknown (GtkCssTokenSource *source,
+ const char *format,
+ ...)
+{
+ va_list args;
+ GError *error;
+
+ va_start (args, format);
+ error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE,
+ format, args);
+ gtk_css_token_source_emit_error (source, error);
+ g_error_free (error);
+ va_end (args);
+}
+
+void
+gtk_css_token_source_deprecated (GtkCssTokenSource *source,
+ const char *format,
+ ...)
+{
+ va_list args;
+ GError *error;
+
+ va_start (args, format);
+ error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+ format, args);
+ gtk_css_token_source_emit_error (source, error);
+ g_error_free (error);
+ va_end (args);
+}
+
diff --git a/gtk/gtkcsstokensourceprivate.h b/gtk/gtkcsstokensourceprivate.h
new file mode 100644
index 0000000..7316c19
--- /dev/null
+++ b/gtk/gtkcsstokensourceprivate.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2016 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__
+#define __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__
+
+#include <glib-object.h>
+#include "gtk/gtkcsstokenizerprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCssTokenSource GtkCssTokenSource;
+typedef struct _GtkCssTokenSourceClass GtkCssTokenSourceClass;
+
+struct _GtkCssTokenSource
+{
+ const GtkCssTokenSourceClass *klass;
+ gint ref_count;
+ GSList *blocks; /* of GPOINTER_TO_UINT(GtkCssTokenType) */
+};
+
+struct _GtkCssTokenSourceClass
+{
+ void (* finalize) (GtkCssTokenSource *source);
+ void (* consume_token) (GtkCssTokenSource *source);
+ const GtkCssToken * (* get_token) (GtkCssTokenSource *source);
+ void (* error) (GtkCssTokenSource *source,
+ const GError *error);
+};
+
+GtkCssTokenSource * gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer);
+GtkCssTokenSource * gtk_css_token_source_new_for_part (GtkCssTokenSource *source,
+ GtkCssTokenType end_type);
+
+GtkCssTokenSource * gtk_css_token_source_ref (GtkCssTokenSource *source);
+void gtk_css_token_source_unref (GtkCssTokenSource *source);
+
+#define gtk_css_token_source_new(type,klass) ((type *) gtk_css_token_source_alloc (sizeof (type), (klass)))
+GtkCssTokenSource * gtk_css_token_source_alloc (gsize struct_size,
+ const GtkCssTokenSourceClass *klass);
+
+void gtk_css_token_source_consume_token (GtkCssTokenSource *source);
+const GtkCssToken * gtk_css_token_source_get_token (GtkCssTokenSource *source);
+
+GtkCssTokenType gtk_css_token_get_pending_block (GtkCssTokenSource *source);
+
+void gtk_css_token_source_consume_all (GtkCssTokenSource *source);
+gboolean gtk_css_token_source_consume_whitespace (GtkCssTokenSource *source);
+
+void gtk_css_token_source_emit_error (GtkCssTokenSource *source,
+ const GError *error);
+void gtk_css_token_source_error (GtkCssTokenSource *source,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
+void gtk_css_token_source_unknown (GtkCssTokenSource *source,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
+void gtk_css_token_source_deprecated (GtkCssTokenSource *source,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]