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:
Benjamin Otte
2016-03-19 05:02:43 +01:00
parent 28babd269b
commit ae248b3443
5 changed files with 148 additions and 4 deletions

View File

@@ -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;

View File

@@ -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 *

View File

@@ -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, &GTK_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)
{

View File

@@ -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);

View File

@@ -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 *