diff --git a/gtk/Makefile.am b/gtk/Makefile.am index a73ffa78a9..c7aba5c2b3 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 0000000000..d074a4a3c3 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..fa72a63f25 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..fb449fd078 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..6a07b60b05 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 9309de5d6f..c0f9ef071a 100644 --- a/gtk/gtkcssselector.c +++ b/gtk/gtkcssselector.c @@ -25,6 +25,8 @@ #include "gtkcssprovider.h" #include "gtkstylecontextprivate.h" +#include +#include #if defined(_MSC_VER) && _MSC_VER >= 1500 # include #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 64eb13d709..55945adf42 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 0000000000..a543a2cc55 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..14ca8e093c --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..74df7fa71d --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..ef5b936b81 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..03a027bf87 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..f2d9132752 --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..069cf9bbbe --- /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 . + * + * Authors: Benjamin Otte + */ + +#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 0000000000..7316c19440 --- /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 . + * + * Authors: Benjamin Otte + */ + +#ifndef __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__ +#define __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__ + +#include +#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__ */