* 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, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcssparserprivate.h"
+#include "gtkwin32themeprivate.h"
#include <errno.h>
#include <string.h>
parser->user_data = user_data;
parser->line_start = data;
- parser->line = 1;
+ parser->line = 0;
return parser;
}
return *parser->data == c;
}
+gboolean
+_gtk_css_parser_has_prefix (GtkCssParser *parser,
+ const char *prefix)
+{
+ g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+
+ return g_ascii_strncasecmp (parser->data, prefix, strlen (prefix)) == 0;
+}
+
guint
_gtk_css_parser_get_line (GtkCssParser *parser)
{
return NULL;
}
-char *
-_gtk_css_parser_read_uri (GtkCssParser *parser)
-{
- char *result;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
-
- if (!_gtk_css_parser_try (parser, "url(", TRUE))
- {
- _gtk_css_parser_error (parser, "expected 'url('");
- return NULL;
- }
-
- _gtk_css_parser_skip_whitespace (parser);
-
- if (_gtk_css_parser_is_string (parser))
- {
- result = _gtk_css_parser_read_string (parser);
- }
- else
- {
- GString *str = g_string_new (NULL);
-
- while (_gtk_css_parser_read_char (parser, str, URLCHAR))
- ;
- result = g_string_free (str, FALSE);
- if (result == NULL)
- _gtk_css_parser_error (parser, "not a url");
- }
-
- if (result == NULL)
- return NULL;
-
- _gtk_css_parser_skip_whitespace (parser);
-
- if (*parser->data != ')')
- {
- _gtk_css_parser_error (parser, "missing ')' for url");
- g_free (result);
- return NULL;
- }
-
- parser->data++;
-
- _gtk_css_parser_skip_whitespace (parser);
-
- return result;
-}
-
gboolean
_gtk_css_parser_try_int (GtkCssParser *parser,
int *value)
return TRUE;
}
+gboolean
+_gtk_css_parser_has_number (GtkCssParser *parser)
+{
+ /* ahem */
+ return strchr ("+-0123456789.", parser->data[0]) != NULL;
+}
+
+gboolean
+_gtk_css_parser_read_number (GtkCssParser *parser,
+ GtkCssNumber *number,
+ 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 }
+ };
+ char *end, *unit;
+
+ g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+ g_return_val_if_fail (number != NULL, FALSE);
+
+ errno = 0;
+ number->unit = GTK_CSS_NUMBER;
+ number->value = g_ascii_strtod (parser->data, &end);
+ if (errno)
+ {
+ _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno));
+ return FALSE;
+ }
+ if (parser->data == end)
+ {
+ _gtk_css_parser_error (parser, "not a number");
+ return FALSE;
+ }
+
+ parser->data = end;
+
+ if (flags & GTK_CSS_POSITIVE_ONLY &&
+ number->value < 0)
+ {
+ _gtk_css_parser_error (parser, "negative values are not allowed.");
+ return FALSE;
+ }
+
+ unit = _gtk_css_parser_try_ident (parser, FALSE);
+
+ if (unit)
+ {
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (units); i++)
+ {
+ if (flags & units[i].required_flags &&
+ g_ascii_strcasecmp (unit, units[i].name) == 0)
+ break;
+ }
+
+ if (i >= G_N_ELEMENTS (units))
+ {
+ _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit);
+ g_free (unit);
+ return FALSE;
+ }
+
+ number->unit = units[i].unit;
+ g_free (unit);
+ }
+ else
+ {
+ if ((flags & GTK_CSS_PARSE_PERCENT) &&
+ _gtk_css_parser_try (parser, "%", FALSE))
+ {
+ number->unit = GTK_CSS_PERCENT;
+ }
+ else if (number->value == 0.0)
+ {
+ if (flags & GTK_CSS_PARSE_NUMBER)
+ number->unit = GTK_CSS_NUMBER;
+ else if (flags & GTK_CSS_PARSE_LENGTH)
+ number->unit = GTK_CSS_PX;
+ else
+ number->unit = GTK_CSS_PERCENT;
+ }
+ else if (flags & GTK_CSS_NUMBER_AS_PIXELS)
+ {
+ GError *error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+ "Not using units is deprecated. Assuming 'px'.");
+ _gtk_css_parser_take_error (parser, error);
+ number->unit = GTK_CSS_PX;
+ }
+ else if (flags & GTK_CSS_PARSE_NUMBER)
+ {
+ number->unit = GTK_CSS_NUMBER;
+ }
+ else
+ {
+ _gtk_css_parser_error (parser, "Unit is missing.");
+ return FALSE;
+ }
+ }
+
+ _gtk_css_parser_skip_whitespace (parser);
+
+ return TRUE;
+}
+
+/* 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;
+}
+
+gboolean
+_gtk_css_parser_try_enum (GtkCssParser *parser,
+ GType enum_type,
+ int *value)
+{
+ GEnumClass *enum_class;
+ gboolean result;
+ const char *start;
+ char *str;
+
+ g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ result = FALSE;
+
+ enum_class = g_type_class_ref (enum_type);
+
+ start = parser->data;
+
+ str = _gtk_css_parser_try_ident (parser, TRUE);
+ if (str == NULL)
+ return FALSE;
+
+ if (enum_class->n_values)
+ {
+ GEnumValue *enum_value;
+
+ for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
+ {
+ if (enum_value->value_nick &&
+ g_ascii_strcasecmp (str, enum_value->value_nick) == 0)
+ {
+ *value = enum_value->value;
+ result = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_free (str);
+ g_type_class_unref (enum_class);
+
+ if (!result)
+ parser->data = start;
+
+ return result;
+}
+
typedef enum {
COLOR_RGBA,
COLOR_RGB,
COLOR_DARKER,
COLOR_SHADE,
COLOR_ALPHA,
- COLOR_MIX
+ COLOR_MIX,
+ COLOR_WIN32
} ColorType;
static GtkSymbolicColor *
symbolic = gtk_symbolic_color_new_literal (&rgba);
}
+ else if (color == COLOR_WIN32)
+ {
+ symbolic = _gtk_win32_theme_color_parse (parser);
+ if (symbolic == NULL)
+ return NULL;
+ }
else
{
child1 = _gtk_css_parser_read_symbolic_color (parser);
{
GtkSymbolicColor *symbolic;
guint color;
- const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix" };
+ const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix",
+ GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME};
char *name;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
+ if (_gtk_css_parser_try (parser, "transparent", TRUE))
+ {
+ GdkRGBA transparent = { 0, 0, 0, 0 };
+
+ return gtk_symbolic_color_new_literal (&transparent);
+ }
+
if (_gtk_css_parser_try (parser, "@", FALSE))
{
name = _gtk_css_parser_try_name (parser, TRUE);
return NULL;
}
+GFile *
+_gtk_css_parser_read_url (GtkCssParser *parser,
+ GFile *base)
+{
+ gchar *path;
+ char *scheme;
+ GFile *file;
+
+ if (_gtk_css_parser_try (parser, "url", FALSE))
+ {
+ if (!_gtk_css_parser_try (parser, "(", TRUE))
+ {
+ _gtk_css_parser_skip_whitespace (parser);
+ if (_gtk_css_parser_try (parser, "(", TRUE))
+ {
+ GError *error;
+
+ error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+ "Whitespace between 'url' and '(' is deprecated");
+
+ _gtk_css_parser_take_error (parser, error);
+ }
+ else
+ {
+ _gtk_css_parser_error (parser, "Expected '(' after 'url'");
+ return NULL;
+ }
+ }
+
+ path = _gtk_css_parser_read_string (parser);
+ if (path == NULL)
+ return NULL;
+
+ if (!_gtk_css_parser_try (parser, ")", TRUE))
+ {
+ _gtk_css_parser_error (parser, "No closing ')' found for 'url'");
+ g_free (path);
+ return NULL;
+ }
+
+ scheme = g_uri_parse_scheme (path);
+ if (scheme != NULL)
+ {
+ file = g_file_new_for_uri (path);
+ g_free (path);
+ g_free (scheme);
+ return file;
+ }
+ }
+ else
+ {
+ path = _gtk_css_parser_try_name (parser, TRUE);
+ if (path == NULL)
+ {
+ _gtk_css_parser_error (parser, "Not a valid url");
+ return NULL;
+ }
+ }
+
+ file = g_file_resolve_relative_path (base, path);
+ g_free (path);
+
+ return file;
+}
+
void
_gtk_css_parser_resync_internal (GtkCssParser *parser,
gboolean sync_at_semicolon,
case '(':
parser->data++;
_gtk_css_parser_resync (parser, FALSE, ')');
- parser->data++;
+ if (*parser->data)
+ parser->data++;
break;
case '[':
parser->data++;
_gtk_css_parser_resync (parser, FALSE, ']');
- parser->data++;
+ if (*parser->data)
+ parser->data++;
break;
case '{':
parser->data++;
_gtk_css_parser_resync (parser, FALSE, '}');
- parser->data++;
+ if (*parser->data)
+ parser->data++;
if (sync_at_semicolon || !terminator)
{
_gtk_css_parser_skip_whitespace (parser);
}
parser->data++;
continue;
+ case '\0':
+ break;
case '/':
default:
parser->data++;