+gboolean
+_gtk_css_parser_has_number (GtkCssParser *parser)
+{
+ /* ahem */
+ return strchr ("+-0123456789.", parser->data[0]) != NULL;
+}
+
+GtkCssValue *
+_gtk_css_number_value_parse (GtkCssParser *parser,
+ GtkCssNumberParseFlags flags)
+{
+ static const struct {
+ const char *name;
+ GtkCssUnit unit;
+ GtkCssNumberParseFlags required_flags;
+ } units[] = {
+ { "px", GTK_CSS_PX, GTK_CSS_PARSE_LENGTH },
+ { "pt", GTK_CSS_PT, GTK_CSS_PARSE_LENGTH },
+ { "em", GTK_CSS_EM, GTK_CSS_PARSE_LENGTH },
+ { "ex", GTK_CSS_EX, GTK_CSS_PARSE_LENGTH },
+ { "pc", GTK_CSS_PC, GTK_CSS_PARSE_LENGTH },
+ { "in", GTK_CSS_IN, GTK_CSS_PARSE_LENGTH },
+ { "cm", GTK_CSS_CM, GTK_CSS_PARSE_LENGTH },
+ { "mm", GTK_CSS_MM, GTK_CSS_PARSE_LENGTH },
+ { "rad", GTK_CSS_RAD, GTK_CSS_PARSE_ANGLE },
+ { "deg", GTK_CSS_DEG, GTK_CSS_PARSE_ANGLE },
+ { "grad", GTK_CSS_GRAD, GTK_CSS_PARSE_ANGLE },
+ { "turn", GTK_CSS_TURN, GTK_CSS_PARSE_ANGLE },
+ { "s", GTK_CSS_S, GTK_CSS_PARSE_TIME },
+ { "ms", GTK_CSS_MS, GTK_CSS_PARSE_TIME }
+ };
+ char *end, *unit_name;
+ double value;
+ GtkCssUnit unit;
+
+ g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
+
+ errno = 0;
+ value = g_ascii_strtod (parser->data, &end);
+ if (errno)
+ {
+ _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno));
+ return NULL;
+ }
+ if (parser->data == end)
+ {
+ _gtk_css_parser_error (parser, "not a number");
+ return NULL;
+ }
+
+ parser->data = end;
+
+ if (flags & GTK_CSS_POSITIVE_ONLY &&
+ value < 0)
+ {
+ _gtk_css_parser_error (parser, "negative values are not allowed.");
+ return NULL;
+ }
+
+ unit_name = _gtk_css_parser_try_ident (parser, FALSE);
+
+ if (unit_name)
+ {
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (units); i++)
+ {
+ if (flags & units[i].required_flags &&
+ g_ascii_strcasecmp (unit_name, units[i].name) == 0)
+ break;
+ }
+
+ if (i >= G_N_ELEMENTS (units))
+ {
+ _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit_name);
+ g_free (unit_name);
+ return NULL;
+ }
+
+ unit = units[i].unit;
+
+ g_free (unit_name);
+ }
+ else
+ {
+ if ((flags & GTK_CSS_PARSE_PERCENT) &&
+ _gtk_css_parser_try (parser, "%", FALSE))
+ {
+ unit = GTK_CSS_PERCENT;
+ }
+ else if (value == 0.0)
+ {
+ if (flags & GTK_CSS_PARSE_NUMBER)
+ unit = GTK_CSS_NUMBER;
+ else if (flags & GTK_CSS_PARSE_LENGTH)
+ unit = GTK_CSS_PX;
+ else if (flags & GTK_CSS_PARSE_ANGLE)
+ unit = GTK_CSS_DEG;
+ else if (flags & GTK_CSS_PARSE_TIME)
+ unit = GTK_CSS_S;
+ else
+ unit = GTK_CSS_PERCENT;
+ }
+ else if (flags & GTK_CSS_NUMBER_AS_PIXELS)
+ {
+ _gtk_css_parser_error_full (parser,
+ GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+ "Not using units is deprecated. Assuming 'px'.");
+ unit = GTK_CSS_PX;
+ }
+ else if (flags & GTK_CSS_PARSE_NUMBER)
+ {
+ unit = GTK_CSS_NUMBER;
+ }
+ else
+ {
+ _gtk_css_parser_error (parser, "Unit is missing.");
+ return NULL;
+ }
+ }
+
+ _gtk_css_parser_skip_whitespace (parser);
+
+ return _gtk_css_number_value_new (value, unit);
+}
+
+/* XXX: we should introduce GtkCssLenght that deals with
+ * different kind of units */
+gboolean
+_gtk_css_parser_try_length (GtkCssParser *parser,
+ int *value)
+{
+ if (!_gtk_css_parser_try_int (parser, value))
+ return FALSE;
+
+ /* FIXME: _try_uint skips spaces while the
+ * spec forbids them
+ */
+ _gtk_css_parser_try (parser, "px", TRUE);
+
+ return TRUE;
+}
+