css: Add gtk_style_property_token_parse()

Slowly move the token parser into CSS value parsing.
This commit is contained in:
Benjamin Otte
2016-03-15 06:47:00 +01:00
parent 257273c439
commit 9c02a600b2
9 changed files with 292 additions and 37 deletions

View File

@@ -43,6 +43,14 @@ gtk_css_custom_property_parse_value (GtkStyleProperty *property,
return NULL;
}
static GtkCssValue *
gtk_css_custom_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
gtk_css_token_source_unknown (source, "Custom CSS properties are no longer supported.");
return NULL;
}
static void
gtk_css_custom_property_query (GtkStyleProperty *property,
GValue *value,
@@ -81,6 +89,7 @@ _gtk_css_custom_property_class_init (GtkCssCustomPropertyClass *klass)
GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
property_class->parse_value = gtk_css_custom_property_parse_value;
property_class->token_parse = gtk_css_custom_property_token_parse;
property_class->query = gtk_css_custom_property_query;
property_class->assign = gtk_css_custom_property_assign;
}

View File

@@ -26,9 +26,8 @@
typedef struct _GtkCssDeclarationPrivate GtkCssDeclarationPrivate;
struct _GtkCssDeclarationPrivate {
GtkCssStyleDeclaration *style;
char *name;
GtkStyleProperty *prop;
char *value;
GtkCssValue *value;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssDeclaration, gtk_css_declaration, G_TYPE_OBJECT)
@@ -39,8 +38,8 @@ gtk_css_declaration_finalize (GObject *object)
GtkCssDeclaration *declaration = GTK_CSS_DECLARATION (object);
GtkCssDeclarationPrivate *priv = gtk_css_declaration_get_instance_private (declaration);
g_free (priv->name);
g_free (priv->value);
if (priv->value)
_gtk_css_value_unref (priv->value);
G_OBJECT_CLASS (gtk_css_declaration_parent_class)->finalize (object);
}
@@ -58,24 +57,6 @@ gtk_css_declaration_init (GtkCssDeclaration *declaration)
{
}
GtkCssDeclaration *
gtk_css_declaration_new (GtkCssStyleDeclaration *style,
const char *name,
const char *value)
{
GtkCssDeclarationPrivate *priv;
GtkCssDeclaration *result;
result = g_object_new (GTK_TYPE_CSS_DECLARATION, NULL);
priv = gtk_css_declaration_get_instance_private (result);
priv->style = style;
priv->name = g_strdup (name);
priv->value = g_strdup (value);
return result;
}
GtkCssDeclaration *
gtk_css_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source)
@@ -83,6 +64,7 @@ gtk_css_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssDeclarationPrivate *priv;
const GtkCssToken *token;
GtkCssDeclaration *decl;
char *name;
decl = g_object_new (GTK_TYPE_CSS_DECLARATION, NULL);
priv = gtk_css_declaration_get_instance_private (decl);
@@ -99,25 +81,40 @@ gtk_css_declaration_new_parse (GtkCssStyleDeclaration *style,
g_object_unref (decl);
return NULL;
}
priv->name = g_strdup (token->string.string);
priv->prop = _gtk_style_property_lookup (priv->name);
name = g_utf8_strdown (token->string.string, -1);
priv->prop = _gtk_style_property_lookup (name);
if (priv->prop == NULL)
gtk_css_token_source_unknown (source, "Unknown property name '%s'", priv->name);
else if (!g_str_equal (priv->name, _gtk_style_property_get_name (priv->prop)))
{
gtk_css_token_source_unknown (source, "Unknown property name '%s'", token->string.string);
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
g_free (name);
return NULL;
}
else if (!g_str_equal (name, _gtk_style_property_get_name (priv->prop)))
gtk_css_token_source_deprecated (source,
"The '%s' property has been renamed to '%s'",
priv->name, _gtk_style_property_get_name (priv->prop));
name, _gtk_style_property_get_name (priv->prop));
gtk_css_token_source_consume_token (source);
gtk_css_token_source_consume_whitespace (source);
g_free (name);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
gtk_css_token_source_error (source, "No colon following property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
priv->value = gtk_css_token_source_consume_to_string (source);
gtk_css_token_source_consume_token (source);
priv->value = gtk_style_property_token_parse (priv->prop, source);
if (priv->value == NULL)
{
g_object_unref (decl);
return NULL;
}
return decl;
}

View File

@@ -75,6 +75,7 @@ do_the_tokenizer (const char *data)
gtk_css_tokenizer_unref (tokenizer);
#else
#if 0
GtkCssStyleSheet *sheet;
GtkCssTokenSource *source;
GtkCssTokenizer *tokenizer;
@@ -91,6 +92,7 @@ do_the_tokenizer (const char *data)
gtk_css_tokenizer_unref (tokenizer);
g_bytes_unref (bytes);
#endif
#endif
}
GtkCssParser *

View File

@@ -156,6 +156,112 @@ gtk_css_shorthand_property_parse_value (GtkStyleProperty *property,
return result;
}
static GtkCssValue *
gtk_css_shorthand_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
const GtkCssToken *token;
GtkCssValue **data;
GtkCssValue *result;
guint i;
data = g_new0 (GtkCssValue *, shorthand->subproperties->len);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "initial"))
{
/* the initial value can be explicitly specified with the
* initial keyword which all properties accept.
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
data[i] = _gtk_css_initial_value_new ();
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "inherit"))
{
/* All properties accept the inherit value which
* explicitly specifies that the value will be determined
* by inheritance. The inherit value can be used to
* strengthen inherited values in the cascade, and it can
* also be used on properties that are not normally inherited.
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
data[i] = _gtk_css_inherit_value_new ();
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "unset"))
{
/* If the cascaded value of a property is the unset keyword,
* then if it is an inherited property, this is treated as
* inherit, and if it is not, this is treated as initial.
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
data[i] = _gtk_css_unset_value_new ();
}
gtk_css_token_source_consume_token (source);
}
else if (!shorthand->token_parse (shorthand, data, source))
{
for (i = 0; i < shorthand->subproperties->len; i++)
{
if (data[i] != NULL)
_gtk_css_value_unref (data[i]);
}
g_free (data);
return NULL;
}
/* All values that aren't set by the parse func are set to their
* default values here.
* XXX: Is the default always initial or can it be inherit? */
for (i = 0; i < shorthand->subproperties->len; i++)
{
if (data[i] == NULL)
data[i] = _gtk_css_initial_value_new ();
}
result = _gtk_css_array_value_new_from_array (data, shorthand->subproperties->len);
g_free (data);
return result;
}
static void
forward_error_to_source (GtkCssParser *parser,
const GError *error,
gpointer source)
{
/* XXX: This is bad because it doesn't emit the error on the right token */
gtk_css_token_source_emit_error (source, error);
}
static gboolean
gtk_css_shorthand_token_parse_default (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssTokenSource *source)
{
GtkCssParser *parser;
char *str;
gboolean result;
str = gtk_css_token_source_consume_to_string (source);
parser = _gtk_css_parser_new (str,
NULL,
forward_error_to_source,
source);
result = shorthand->parse (shorthand, values, parser);
_gtk_css_parser_free (parser);
g_free (str);
return result;
}
static void
_gtk_css_shorthand_property_class_init (GtkCssShorthandPropertyClass *klass)
{
@@ -175,12 +281,15 @@ _gtk_css_shorthand_property_class_init (GtkCssShorthandPropertyClass *klass)
property_class->assign = _gtk_css_shorthand_property_assign;
property_class->query = _gtk_css_shorthand_property_query;
property_class->parse_value = gtk_css_shorthand_property_parse_value;
property_class->token_parse = gtk_css_shorthand_property_token_parse;
}
static void
_gtk_css_shorthand_property_init (GtkCssShorthandProperty *shorthand)
{
shorthand->subproperties = g_ptr_array_new_with_free_func (g_object_unref);
shorthand->token_parse = gtk_css_shorthand_token_parse_default;
}
GtkCssStyleProperty *

View File

@@ -41,6 +41,9 @@ typedef struct _GtkCssShorthandPropertyClass GtkCssShorthandPropertyClass;
typedef gboolean (* GtkCssShorthandPropertyParseFunc) (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser);
typedef gboolean (* GtkCssShorthandPropertyTokenParseFunc) (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssTokenSource *source);
typedef void (* GtkCssShorthandPropertyAssignFunc) (GtkCssShorthandProperty *shorthand,
GtkStyleProperties *props,
GtkStateFlags state,
@@ -57,6 +60,7 @@ struct _GtkCssShorthandProperty
GPtrArray *subproperties;
GtkCssShorthandPropertyParseFunc parse;
GtkCssShorthandPropertyTokenParseFunc token_parse;
GtkCssShorthandPropertyAssignFunc assign;
GtkCssShorthandPropertyQueryFunc query;
};

View File

@@ -192,6 +192,80 @@ gtk_css_style_property_parse_value (GtkStyleProperty *property,
return (* style_property->parse_value) (style_property, parser);
}
static void
forward_error_to_source (GtkCssParser *parser,
const GError *error,
gpointer source)
{
/* XXX: This is bad because it doesn't emit the error on the right token */
gtk_css_token_source_emit_error (source, error);
}
static GtkCssValue *
gtk_css_style_property_token_parse_default (GtkCssStyleProperty *property,
GtkCssTokenSource *source)
{
GtkCssParser *parser;
GtkCssValue *value;
char *str;
str = gtk_css_token_source_consume_to_string (source);
parser = _gtk_css_parser_new (str,
NULL,
forward_error_to_source,
source);
value = property->parse_value (property, parser);
_gtk_css_parser_free (parser);
g_free (str);
return value;
}
static GtkCssValue *
gtk_css_style_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
GtkCssStyleProperty *style_property = GTK_CSS_STYLE_PROPERTY (property);
const GtkCssToken *token;
GtkCssValue *value;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "initial"))
{
/* the initial value can be explicitly specified with the
* initial keyword which all properties accept.
*/
value = _gtk_css_initial_value_new ();
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "inherit"))
{
/* All properties accept the inherit value which
* explicitly specifies that the value will be determined
* by inheritance. The inherit value can be used to
* strengthen inherited values in the cascade, and it can
* also be used on properties that are not normally inherited.
*/
value = _gtk_css_inherit_value_new ();
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "unset"))
{
/* If the cascaded value of a property is the unset keyword,
* then if it is an inherited property, this is treated as
* inherit, and if it is not, this is treated as initial.
*/
value = _gtk_css_unset_value_new ();
gtk_css_token_source_consume_token (source);
}
else
{
value = (* style_property->token_parse) (style_property, source);
}
return value;
}
static void
_gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
{
@@ -242,6 +316,7 @@ _gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
property_class->assign = _gtk_css_style_property_assign;
property_class->query = _gtk_css_style_property_query;
property_class->parse_value = gtk_css_style_property_parse_value;
property_class->token_parse = gtk_css_style_property_token_parse;
klass->style_properties = g_ptr_array_new ();
@@ -260,6 +335,7 @@ static void
_gtk_css_style_property_init (GtkCssStyleProperty *property)
{
property->parse_value = gtk_css_style_property_real_parse_value;
property->token_parse = gtk_css_style_property_token_parse_default;
}
/**

View File

@@ -34,13 +34,15 @@ G_BEGIN_DECLS
typedef struct _GtkCssStyleProperty GtkCssStyleProperty;
typedef struct _GtkCssStylePropertyClass GtkCssStylePropertyClass;
typedef GtkCssValue * (* GtkCssStylePropertyParseFunc) (GtkCssStyleProperty *property,
GtkCssParser *parser);
typedef void (* GtkCssStylePropertyQueryFunc) (GtkCssStyleProperty *property,
const GtkCssValue *cssvalue,
GValue *value);
typedef GtkCssValue * (* GtkCssStylePropertyAssignFunc) (GtkCssStyleProperty *property,
const GValue *value);
typedef GtkCssValue * (* GtkCssStylePropertyParseFunc) (GtkCssStyleProperty *property,
GtkCssParser *parser);
typedef GtkCssValue * (* GtkCssStylePropertyTokenParseFunc) (GtkCssStyleProperty *property,
GtkCssTokenSource *source);
typedef void (* GtkCssStylePropertyQueryFunc) (GtkCssStyleProperty *property,
const GtkCssValue *cssvalue,
GValue *value);
typedef GtkCssValue * (* GtkCssStylePropertyAssignFunc) (GtkCssStyleProperty *property,
const GValue *value);
struct _GtkCssStyleProperty
{
GtkStyleProperty parent;
@@ -52,6 +54,7 @@ struct _GtkCssStyleProperty
guint animated :1;
GtkCssStylePropertyParseFunc parse_value;
GtkCssStylePropertyTokenParseFunc token_parse;
GtkCssStylePropertyQueryFunc query_value;
GtkCssStylePropertyAssignFunc assign_value;
};

View File

@@ -158,6 +158,56 @@ _gtk_style_property_parse_value (GtkStyleProperty *property,
return klass->parse_value (property, parser);
}
/**
* _gtk_style_property_parse_value:
* @property: the property
* @parser: the parser to parse from
*
* Tries to parse the given @property from the given @parser into
* @value. The type that @value will be assigned is dependant on
* the parser and no assumptions must be made about it. If the
* parsing fails, %FALSE will be returned and @value will be
* left uninitialized.
*
* Only if @property is a #GtkCssShorthandProperty, the @value will
* always be a #GtkCssValue whose values can be queried with
* _gtk_css_array_value_get_nth().
*
* Returns: %NULL on failure or the parsed #GtkCssValue
**/
GtkCssValue *
gtk_style_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
GtkStylePropertyClass *klass;
GtkCssValue *value;
g_return_val_if_fail (GTK_IS_STYLE_PROPERTY (property), NULL);
g_return_val_if_fail (source != NULL, NULL);
klass = GTK_STYLE_PROPERTY_GET_CLASS (property);
gtk_css_token_source_consume_whitespace (source);
value = klass->token_parse (property, source);
if (value == NULL)
return NULL;
gtk_css_token_source_consume_whitespace (source);
if (!gtk_css_token_is (gtk_css_token_source_get_token (source),
GTK_CSS_TOKEN_EOF))
{
gtk_css_token_source_error (source, "Junk at end of value");
gtk_css_token_source_consume_all (source);
_gtk_css_value_unref (value);
return NULL;
}
return value;
}
/**
* _gtk_style_property_assign:
* @property: the property

View File

@@ -19,6 +19,7 @@
#define __GTK_STYLEPROPERTY_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtkcssvalueprivate.h"
@@ -57,8 +58,10 @@ struct _GtkStylePropertyClass
GValue *value,
GtkStyleQueryFunc query_func,
gpointer query_data);
GtkCssValue * (* parse_value) (GtkStyleProperty * property,
GtkCssValue * (* parse_value) (GtkStyleProperty *property,
GtkCssParser *parser);
GtkCssValue * (* token_parse) (GtkStyleProperty *property,
GtkCssTokenSource *source);
GHashTable *properties;
};
@@ -76,6 +79,8 @@ const char * _gtk_style_property_get_name (GtkStyleProperty
GtkCssValue * _gtk_style_property_parse_value (GtkStyleProperty * property,
GtkCssParser *parser);
GtkCssValue * gtk_style_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source);
GType _gtk_style_property_get_value_type(GtkStyleProperty * property);
void _gtk_style_property_query (GtkStyleProperty * property,