cssimage: Add token parser for url() images
This requires adding location information to GtkCssTokenSource, so that we can resolve relative URLs.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__
|
||||
#define __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
#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);
|
||||
|
||||
@@ -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 *
|
||||
|
||||
Reference in New Issue
Block a user