[gtk+/wip/otte/tokenizer: 37/42] cssimage: Add token parser for url() images



commit b0a0d5b285df19cba294d473e63852b85042221f
Author: Benjamin Otte <otte redhat com>
Date:   Sat Mar 19 05:02:43 2016 +0100

    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        |  109 +++++++++++++++++++++++++++++++++++++++-
 gtk/gtkcsstokensourceprivate.h |   10 +++-
 gtk/inspector/css-editor.c     |    7 +++
 5 files changed, 147 insertions(+), 4 deletions(-)
---
diff --git a/gtk/gtkcssimageurl.c b/gtk/gtkcssimageurl.c
index 7e83f13..9f610c5 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 ef65c61..70ed6d8 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 aec0cb3..12e4232 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
@@ -80,22 +83,35 @@ gtk_css_token_source_tokenizer_error (GtkCssTokenSource *source,
   g_print ("ERROR: %s\n", 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;
 }
@@ -156,11 +172,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 *
@@ -414,6 +439,82 @@ 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;
+        }
+      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)
 {
@@ -481,6 +582,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 8547611..7b82762 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 <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);
diff --git a/gtk/inspector/css-editor.c b/gtk/inspector/css-editor.c
index 3b3210a..21da13e 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 *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]