From ae248b3443c37188759157460c268fa41013e848 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 19 Mar 2016 05:02:43 +0100 Subject: [PATCH] cssimage: Add token parser for url() images This requires adding location information to GtkCssTokenSource, so that we can resolve relative URLs. --- gtk/gtkcssimageurl.c | 14 +++++ gtk/gtkcssrule.c | 11 +++- gtk/gtkcsstokensource.c | 110 ++++++++++++++++++++++++++++++++- gtk/gtkcsstokensourceprivate.h | 10 ++- gtk/inspector/css-editor.c | 7 +++ 5 files changed, 148 insertions(+), 4 deletions(-) diff --git a/gtk/gtkcssimageurl.c b/gtk/gtkcssimageurl.c index 7e83f13c57..9f610c5bfd 100644 --- a/gtk/gtkcssimageurl.c +++ b/gtk/gtkcssimageurl.c @@ -163,6 +163,19 @@ gtk_css_image_url_parse (GtkCssImage *image, return TRUE; } +static gboolean +gtk_css_image_url_token_parse (GtkCssImage *image, + GtkCssTokenSource *source) +{ + GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image); + + url->file = gtk_css_token_source_consume_url (source); + if (url->file == NULL) + return FALSE; + + return TRUE; +} + static void gtk_css_image_url_print (GtkCssImage *image, GString *string) @@ -195,6 +208,7 @@ _gtk_css_image_url_class_init (GtkCssImageUrlClass *klass) image_class->compute = gtk_css_image_url_compute; image_class->draw = gtk_css_image_url_draw; image_class->parse = gtk_css_image_url_parse; + image_class->token_parse = gtk_css_image_url_token_parse; image_class->print = gtk_css_image_url_print; object_class->dispose = gtk_css_image_url_dispose; diff --git a/gtk/gtkcssrule.c b/gtk/gtkcssrule.c index ef65c6110a..70ed6d8e0b 100644 --- a/gtk/gtkcssrule.c +++ b/gtk/gtkcssrule.c @@ -93,11 +93,20 @@ gtk_css_token_source_at_error (GtkCssTokenSource *source, gtk_css_token_source_emit_error (at->source, error); } +static GFile * +gtk_css_token_source_at_get_location (GtkCssTokenSource *source) +{ + GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source; + + return gtk_css_token_source_get_location (at->source); +} + 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_peek_token, - gtk_css_token_source_at_error + gtk_css_token_source_at_error, + gtk_css_token_source_at_get_location, }; static GtkCssTokenSource * diff --git a/gtk/gtkcsstokensource.c b/gtk/gtkcsstokensource.c index ffb3b5658c..9ed2675891 100644 --- a/gtk/gtkcsstokensource.c +++ b/gtk/gtkcsstokensource.c @@ -28,6 +28,7 @@ typedef struct _GtkCssTokenSourceTokenizer GtkCssTokenSourceTokenizer; struct _GtkCssTokenSourceTokenizer { GtkCssTokenSource parent; GtkCssTokenizer *tokenizer; + GFile *location; GtkCssToken current_token; }; @@ -38,6 +39,8 @@ gtk_css_token_source_tokenizer_finalize (GtkCssTokenSource *source) gtk_css_token_clear (&tok->current_token); gtk_css_tokenizer_unref (tok->tokenizer); + if (tok->location) + g_object_unref (tok->location); } static void @@ -85,22 +88,35 @@ gtk_css_token_source_tokenizer_error (GtkCssTokenSource *source, error->message); } +static GFile * +gtk_css_token_source_tokenizer_get_location (GtkCssTokenSource *source) +{ + GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source; + + return tok->location; +} + 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_peek_token, gtk_css_token_source_tokenizer_error, + gtk_css_token_source_tokenizer_get_location, }; GtkCssTokenSource * -gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer) +gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer, + GFile *location) { GtkCssTokenSourceTokenizer *source; g_return_val_if_fail (tokenizer != NULL, NULL); + g_return_val_if_fail (location == NULL || G_IS_FILE (location), NULL); source = gtk_css_token_source_new (GtkCssTokenSourceTokenizer, >K_CSS_TOKEN_SOURCE_TOKENIZER); source->tokenizer = gtk_css_tokenizer_ref (tokenizer); + if (location) + source->location = g_object_ref (location); return &source->parent; } @@ -161,11 +177,20 @@ gtk_css_token_source_part_error (GtkCssTokenSource *source, gtk_css_token_source_emit_error (part->source, error); } +static GFile * +gtk_css_token_source_part_get_location (GtkCssTokenSource *source) +{ + GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source; + + return gtk_css_token_source_get_location (part->source); +} + 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_peek_token, gtk_css_token_source_part_error, + gtk_css_token_source_part_get_location, }; GtkCssTokenSource * @@ -419,6 +444,83 @@ gtk_css_token_source_consume_number (GtkCssTokenSource *source, return TRUE; } +GFile * +gtk_css_token_source_resolve_url (GtkCssTokenSource *source, + const char *url) +{ + char *scheme; + GFile *file, *location, *base; + + scheme = g_uri_parse_scheme (url); + if (scheme != NULL) + { + file = g_file_new_for_uri (url); + g_free (scheme); + return file; + } + + location = gtk_css_token_source_get_location (source); + if (location) + { + base = g_file_get_parent (location); + } + else + { + char *dir = g_get_current_dir (); + base = g_file_new_for_path (dir); + g_free (dir); + } + + file = g_file_resolve_relative_path (base, url); + g_object_unref (base); + + return file; +} + +GFile * +gtk_css_token_source_consume_url (GtkCssTokenSource *source) +{ + const GtkCssToken *token; + GFile *file; + + token = gtk_css_token_source_get_token (source); + if (gtk_css_token_is (token, GTK_CSS_TOKEN_URL)) + { + file = gtk_css_token_source_resolve_url (source, token->string.string); + gtk_css_token_source_consume_token (source); + return file; + } + else if (gtk_css_token_is_function (token, "url")) + { + gtk_css_token_source_consume_token (source); + token = gtk_css_token_source_get_token (source); + if (!gtk_css_token_is (token, GTK_CSS_TOKEN_STRING)) + { + gtk_css_token_source_error (source, "Expected string inside url()"); + gtk_css_token_source_consume_all (source); + return NULL; + } + file = gtk_css_token_source_resolve_url (source, token->string.string); + gtk_css_token_source_consume_token (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 closing ')' for url()"); + gtk_css_token_source_consume_all (source); + g_object_unref (file); + return NULL; + } + gtk_css_token_source_consume_token (source); + return file; + } + else + { + gtk_css_token_source_error (source, "Expected url()"); + gtk_css_token_source_consume_all (source); + return NULL; + } +} + GtkCssTokenType gtk_css_token_get_pending_block (GtkCssTokenSource *source) { @@ -486,6 +588,12 @@ gtk_css_token_source_deprecated (GtkCssTokenSource *source, va_end (args); } +GFile * +gtk_css_token_source_get_location (GtkCssTokenSource *source) +{ + return source->klass->get_location (source); +} + GObject * gtk_css_token_source_get_consumer (GtkCssTokenSource *source) { diff --git a/gtk/gtkcsstokensourceprivate.h b/gtk/gtkcsstokensourceprivate.h index 8547611955..7b82762f4d 100644 --- a/gtk/gtkcsstokensourceprivate.h +++ b/gtk/gtkcsstokensourceprivate.h @@ -20,7 +20,7 @@ #ifndef __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__ #define __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__ -#include +#include #include "gtk/gtkcsstokenizerprivate.h" G_BEGIN_DECLS @@ -44,9 +44,11 @@ struct _GtkCssTokenSourceClass const GtkCssToken * (* peek_token) (GtkCssTokenSource *source); void (* error) (GtkCssTokenSource *source, const GError *error); + GFile * (* get_location) (GtkCssTokenSource *source); }; -GtkCssTokenSource * gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer); +GtkCssTokenSource * gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer, + GFile *location); GtkCssTokenSource * gtk_css_token_source_new_for_part (GtkCssTokenSource *source, GtkCssTokenType end_type); @@ -75,6 +77,9 @@ gboolean gtk_css_token_source_consume_function (GtkCssTokenSour gpointer data); gboolean gtk_css_token_source_consume_number (GtkCssTokenSource *source, double *number); +GFile * gtk_css_token_source_resolve_url (GtkCssTokenSource *source, + const char *url); +GFile * gtk_css_token_source_consume_url (GtkCssTokenSource *source); void gtk_css_token_source_emit_error (GtkCssTokenSource *source, const GError *error); @@ -88,6 +93,7 @@ void gtk_css_token_source_deprecated (GtkCssTokenSour const char *format, ...) G_GNUC_PRINTF(2, 3); +GFile * gtk_css_token_source_get_location (GtkCssTokenSource *source); GObject * gtk_css_token_source_get_consumer (GtkCssTokenSource *source); void gtk_css_token_source_set_consumer (GtkCssTokenSource *source, GObject *consumer); diff --git a/gtk/inspector/css-editor.c b/gtk/inspector/css-editor.c index 3b3210a2f9..21da13e8db 100644 --- a/gtk/inspector/css-editor.c +++ b/gtk/inspector/css-editor.c @@ -194,11 +194,18 @@ gtk_css_chunk_token_source_error (GtkCssTokenSource *source, chunk->error = g_error_copy (error); } +static GFile * +gtk_css_chunk_token_source_get_location (GtkCssTokenSource *source) +{ + return NULL; +} + const GtkCssTokenSourceClass GTK_CSS_CHUNK_TOKEN_SOURCE = { gtk_css_chunk_token_source_finalize, gtk_css_chunk_token_source_consume_token, gtk_css_chunk_token_source_get_token, gtk_css_chunk_token_source_error, + gtk_css_chunk_token_source_get_location, }; static GtkCssTokenSource *