css: Add token parsers for shadows

This also introduces the new idea of check_token() functions. These
functions check if a given function might be the initial token in
parsing a certain value. Implementations for numbers and colors are
included.
This commit is contained in:
Benjamin Otte
2016-03-18 03:27:44 +01:00
parent 567d9887f7
commit d7c8885852
9 changed files with 212 additions and 4 deletions

View File

@@ -919,6 +919,27 @@ parse_percentage (GtkCssTokenSource *source,
}
}
gboolean
gtk_css_color_value_check_token (const GtkCssToken *token)
{
GdkRGBA rgba;
return gtk_css_token_is_ident (token, "currentColor")
|| gtk_css_token_is_ident (token, "transparent")
|| gtk_css_token_is_function (token, "rgb")
|| gtk_css_token_is_function (token, "rgba")
|| gtk_css_token_is_function (token, "lighter")
|| gtk_css_token_is_function (token, "darker")
|| gtk_css_token_is_function (token, "shade")
|| gtk_css_token_is_function (token, "alpha")
|| gtk_css_token_is_function (token, "mix")
|| gtk_css_token_is_function (token, GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_AT_KEYWORD)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED)
|| (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) && gdk_rgba_parse (&rgba, token->string.string));
}
GtkCssValue *
gtk_css_color_value_token_parse (GtkCssTokenSource *source)
{
@@ -967,6 +988,7 @@ gtk_css_color_value_token_parse (GtkCssTokenSource *source)
if (!parse_number (source, &rgba.red) ||
!parse_comma (source) ||
!parse_number (source, &rgba.green) ||
!parse_comma (source) ||
!parse_number (source, &rgba.blue))
return NULL;
rgba.red = CLAMP (rgba.red, 0, 255.0) / 255.0;

View File

@@ -44,6 +44,7 @@ GtkCssValue * _gtk_css_color_value_new_current_color (void);
GtkCssValue * _gtk_css_color_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_color_value_token_parse (GtkCssTokenSource *source);
gboolean gtk_css_color_value_check_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_color_value_resolve (GtkCssValue *color,
GtkStyleProviderPrivate *provider,

View File

@@ -158,6 +158,24 @@ _gtk_css_number_value_parse (GtkCssParser *parser,
return gtk_css_dimension_value_parse (parser, flags);
}
gboolean
gtk_css_number_value_check_token (const GtkCssToken *token)
{
return gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_NUMBER)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_DIMENSION)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_INTEGER_DIMENSION)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE)
|| gtk_css_token_is_function (token, "calc")
|| gtk_css_token_is_function (token, "-gtk-win32-size")
|| gtk_css_token_is_function (token, "-gtk-win32-part-width")
|| gtk_css_token_is_function (token, "-gtk-win32-part-height")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-top")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-left")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-bottom")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-right");
}
GtkCssValue *
gtk_css_number_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)

View File

@@ -62,6 +62,7 @@ GtkCssValue * gtk_css_number_value_transition (GtkCssValue *sta
gboolean gtk_css_number_value_can_parse (GtkCssParser *parser);
GtkCssValue * _gtk_css_number_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags);
gboolean gtk_css_number_value_check_token (const GtkCssToken *token);
GtkCssValue * gtk_css_number_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags);

View File

@@ -240,6 +240,48 @@ _gtk_css_shadows_value_parse (GtkCssParser *parser,
return result;
}
GtkCssValue *
gtk_css_shadows_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode)
{
GtkCssValue *value, *result;
const GtkCssToken *token;
GPtrArray *values;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "none"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_shadows_value_new_none ();
}
values = g_ptr_array_new ();
while (TRUE)
{
value = gtk_css_shadow_value_token_parse (source, box_shadow_mode);
if (value == NULL)
{
g_ptr_array_set_free_func (values, (GDestroyNotify) _gtk_css_value_unref);
g_ptr_array_free (values, TRUE);
return NULL;
}
g_ptr_array_add (values, value);
gtk_css_token_source_consume_whitespace (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COMMA))
break;
gtk_css_token_source_consume_token (source);
gtk_css_token_source_consume_whitespace (source);
}
result = gtk_css_shadows_value_new ((GtkCssValue **) values->pdata, values->len);
g_ptr_array_free (values, TRUE);
return result;
}
gboolean
_gtk_css_shadows_value_is_none (const GtkCssValue *shadows)
{

View File

@@ -25,6 +25,7 @@
#include "gtktypes.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtkroundedboxprivate.h"
@@ -33,6 +34,8 @@ G_BEGIN_DECLS
GtkCssValue * _gtk_css_shadows_value_new_none (void);
GtkCssValue * _gtk_css_shadows_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode);
GtkCssValue * gtk_css_shadows_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode);
gboolean _gtk_css_shadows_value_is_none (const GtkCssValue *shadows);

View File

@@ -293,6 +293,110 @@ fail:
return NULL;
}
GtkCssValue *
gtk_css_shadow_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode)
{
enum {
HOFFSET,
VOFFSET,
RADIUS,
SPREAD,
COLOR,
N_VALUES
};
GtkCssValue *values[N_VALUES] = { NULL, };
gboolean inset = FALSE;
const GtkCssToken *token;
guint i;
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))
{
if (box_shadow_mode && !inset &&
gtk_css_token_is_ident (token, "inset"))
{
inset = TRUE;
gtk_css_token_source_consume_token (source);
gtk_css_token_source_consume_whitespace (source);
}
else if (values[COLOR] == NULL && gtk_css_color_value_check_token (token))
{
values[COLOR] = gtk_css_color_value_token_parse (source);
if (values[COLOR] == NULL)
goto fail;
gtk_css_token_source_consume_whitespace (source);
}
else if (values[HOFFSET] == NULL && gtk_css_number_value_check_token (token))
{
values[HOFFSET] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[HOFFSET] == NULL)
goto fail;
gtk_css_token_source_consume_whitespace (source);
values[VOFFSET] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[VOFFSET] == NULL)
goto fail;
gtk_css_token_source_consume_whitespace (source);
if (gtk_css_number_value_check_token (gtk_css_token_source_get_token (source)))
{
values[RADIUS] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_POSITIVE_ONLY
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[RADIUS] == NULL)
goto fail;
gtk_css_token_source_consume_whitespace (source);
}
else
values[RADIUS] = _gtk_css_number_value_new (0.0, GTK_CSS_PX);
if (box_shadow_mode &&
gtk_css_number_value_check_token (gtk_css_token_source_get_token (source)))
{
values[SPREAD] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[SPREAD] == NULL)
goto fail;
gtk_css_token_source_consume_whitespace (source);
}
else
values[SPREAD] = _gtk_css_number_value_new (0.0, GTK_CSS_PX);
}
else if (values[HOFFSET] == NULL)
{
gtk_css_token_source_error (source, "Expected a shadow definition");
gtk_css_token_source_consume_all (source);
goto fail;
}
else
break;
}
if (values[COLOR] == NULL)
values[COLOR] = _gtk_css_color_value_new_current_color ();
return gtk_css_shadow_value_new (values[HOFFSET], values[VOFFSET],
values[RADIUS], values[SPREAD],
inset, values[COLOR]);
fail:
for (i = 0; i < N_VALUES; i++)
{
if (values[i])
_gtk_css_value_unref (values[i]);
}
return NULL;
}
static gboolean
needs_blur (const GtkCssValue *shadow)
{

View File

@@ -25,6 +25,7 @@
#include "gtktypes.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtkroundedboxprivate.h"
@@ -34,6 +35,8 @@ GtkCssValue * _gtk_css_shadow_value_new_for_transition (GtkCssValue
GtkCssValue * _gtk_css_shadow_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode);
GtkCssValue * gtk_css_shadow_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode);
gboolean _gtk_css_shadow_value_get_inset (const GtkCssValue *shadow);

View File

@@ -932,6 +932,13 @@ box_shadow_value_parse (GtkCssStyleProperty *property,
return _gtk_css_shadows_value_parse (parser, TRUE);
}
static GtkCssValue *
box_shadow_value_token_parse (GtkCssTokenSource *source,
GtkCssStyleProperty *property)
{
return gtk_css_shadows_value_token_parse (source, TRUE);
}
static GtkCssValue *
shadow_value_parse (GtkCssStyleProperty *property,
GtkCssParser *parser)
@@ -939,6 +946,13 @@ shadow_value_parse (GtkCssStyleProperty *property,
return _gtk_css_shadows_value_parse (parser, FALSE);
}
static GtkCssValue *
shadow_value_token_parse (GtkCssTokenSource *source,
GtkCssStyleProperty *property)
{
return gtk_css_shadows_value_token_parse (source, FALSE);
}
static GtkCssValue *
transform_value_parse (GtkCssStyleProperty *property,
GtkCssParser *parser)
@@ -1612,7 +1626,7 @@ _gtk_css_style_property_init_properties (void)
GTK_STYLE_PROPERTY_INHERIT | GTK_STYLE_PROPERTY_ANIMATED,
GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_CLIP,
shadow_value_parse,
gtk_css_style_property_token_parse_default,
shadow_value_token_parse,
NULL,
NULL,
_gtk_css_shadows_value_new_none ());
@@ -1623,7 +1637,7 @@ _gtk_css_style_property_init_properties (void)
GTK_STYLE_PROPERTY_ANIMATED,
GTK_CSS_AFFECTS_BACKGROUND | GTK_CSS_AFFECTS_CLIP,
box_shadow_value_parse,
gtk_css_style_property_token_parse_default,
box_shadow_value_token_parse,
NULL,
NULL,
_gtk_css_shadows_value_new_none ());
@@ -2097,7 +2111,7 @@ _gtk_css_style_property_init_properties (void)
GTK_STYLE_PROPERTY_INHERIT | GTK_STYLE_PROPERTY_ANIMATED,
GTK_CSS_AFFECTS_ICON | GTK_CSS_AFFECTS_SYMBOLIC_ICON | GTK_CSS_AFFECTS_CLIP,
shadow_value_parse,
gtk_css_style_property_token_parse_default,
shadow_value_token_parse,
NULL,
NULL,
_gtk_css_shadows_value_new_none ());