[libshumate] vector: Add background layer



commit 8a04b0344b10511e94eb66d5e48f6d8350550259
Author: James Westman <james jwestman net>
Date:   Mon Aug 23 00:56:21 2021 -0500

    vector: Add background layer
    
    Add layers to ShumateVectorStyle. It reads these layers from a Mapbox
    Style Specification JSON file. So far, only background layers are
    supported because there is no protobuf/MVT parsing capability yet.

 demos/map-style.json                               |  11 +++
 demos/org.gnome.Shumate.Demo.gresources.xml        |   3 +
 demos/shumate-demo-window.c                        |   6 +-
 shumate/meson.build                                |   4 +
 shumate/shumate-vector-style.c                     |  75 ++++++++++++--
 shumate/shumate-vector-style.h                     |   3 +-
 .../shumate-vector-background-layer-private.h      |  32 ++++++
 shumate/vector/shumate-vector-background-layer.c   |  76 ++++++++++++++
 shumate/vector/shumate-vector-layer-private.h      |  41 ++++++++
 shumate/vector/shumate-vector-layer.c              | 110 +++++++++++++++++++++
 tests/data/meson.build                             |   5 +
 tests/data/style.json                              |  11 +++
 tests/data/tests.gresource.xml                     |   6 ++
 tests/meson.build                                  |   4 +
 tests/vector-style.c                               |  26 +++++
 15 files changed, 405 insertions(+), 8 deletions(-)
---
diff --git a/demos/map-style.json b/demos/map-style.json
new file mode 100644
index 0000000..890e370
--- /dev/null
+++ b/demos/map-style.json
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "id": "background",
+      "type": "background",
+      "paint": {
+        "background-color": "#f6f5f4"
+      }
+    }
+  ]
+}
diff --git a/demos/org.gnome.Shumate.Demo.gresources.xml b/demos/org.gnome.Shumate.Demo.gresources.xml
index 6446607..1ebd6cf 100644
--- a/demos/org.gnome.Shumate.Demo.gresources.xml
+++ b/demos/org.gnome.Shumate.Demo.gresources.xml
@@ -6,4 +6,7 @@
   <gresource prefix="/org/gnome/Shumate/Demo/icons">
     <file preprocess="xml-stripblanks">map-marker-symbolic.svg</file>
   </gresource>
+  <gresource prefix="/org/gnome/Shumate/Demo/styles">
+    <file preprocess="json-stripblanks">map-style.json</file>
+  </gresource>
 </gresources>
diff --git a/demos/shumate-demo-window.c b/demos/shumate-demo-window.c
index 311e42e..1d24f24 100644
--- a/demos/shumate-demo-window.c
+++ b/demos/shumate-demo-window.c
@@ -138,6 +138,8 @@ shumate_demo_window_init (ShumateDemoWindow *self)
 {
   ShumateViewport *viewport;
   GtkExpression *expression;
+  g_autoptr(GBytes) bytes = NULL;
+  const char *style_json;
   g_autoptr(ShumateVectorStyle) style = NULL;
   ShumateMapSource *map_source = NULL;
 
@@ -150,7 +152,9 @@ shumate_demo_window_init (ShumateDemoWindow *self)
   gtk_drop_down_set_expression (self->layers_dropdown, expression);
   gtk_drop_down_set_model (self->layers_dropdown, G_LIST_MODEL (self->registry));
 
-  style = shumate_vector_style_create ("{}", NULL);
+  bytes = g_resources_lookup_data ("/org/gnome/Shumate/Demo/styles/map-style.json", 
G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
+  style_json = g_bytes_get_data (bytes, NULL);
+  style = shumate_vector_style_create (style_json, NULL);
 
   map_source = SHUMATE_MAP_SOURCE (shumate_network_tile_source_new_vector_full (
     "vector-tiles",
diff --git a/shumate/meson.build b/shumate/meson.build
index 4cd3ccc..e49354a 100644
--- a/shumate/meson.build
+++ b/shumate/meson.build
@@ -26,6 +26,8 @@ libshumate_private_h = [
   'shumate-kinetic-scrolling-private.h',
   'shumate-marker-private.h',
 
+  'vector/shumate-vector-background-layer-private.h',
+  'vector/shumate-vector-layer-private.h',
   'vector/shumate-vector-utils-private.h',
 ]
 
@@ -52,6 +54,8 @@ libshumate_sources = [
   'shumate-vector-style.c',
   'shumate-viewport.c',
 
+  'vector/shumate-vector-background-layer.c',
+  'vector/shumate-vector-layer.c',
   'vector/shumate-vector-utils.c',
 ]
 
diff --git a/shumate/shumate-vector-style.c b/shumate/shumate-vector-style.c
index 8cc14a6..e6de875 100644
--- a/shumate/shumate-vector-style.c
+++ b/shumate/shumate-vector-style.c
@@ -15,8 +15,11 @@
  * License along with this library; if not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <json-glib/json-glib.h>
 #include <cairo/cairo.h>
 
+#include "vector/shumate-vector-utils-private.h"
+#include "vector/shumate-vector-layer-private.h"
 #include "shumate-vector-style.h"
 
 struct _ShumateVectorStyle
@@ -24,9 +27,14 @@ struct _ShumateVectorStyle
   GObject parent_instance;
 
   char *style_json;
+
+  GPtrArray *layers;
 };
 
-G_DEFINE_TYPE (ShumateVectorStyle, shumate_vector_style, G_TYPE_OBJECT)
+static void shumate_vector_style_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ShumateVectorStyle, shumate_vector_style, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, shumate_vector_style_initable_iface_init))
 
 enum {
   PROP_0,
@@ -52,9 +60,9 @@ shumate_vector_style_create (const char *style_json, GError **error)
 {
   g_return_val_if_fail (style_json != NULL, NULL);
 
-  return g_object_new (SHUMATE_TYPE_VECTOR_STYLE,
-                       "style-json", style_json,
-                       NULL);
+  return g_initable_new (SHUMATE_TYPE_VECTOR_STYLE, NULL, error,
+                         "style-json", style_json,
+                         NULL);
 }
 
 
@@ -63,6 +71,7 @@ shumate_vector_style_finalize (GObject *object)
 {
   ShumateVectorStyle *self = (ShumateVectorStyle *)object;
 
+  g_clear_pointer (&self->layers, g_ptr_array_unref);
   g_clear_pointer (&self->style_json, g_free);
 
   G_OBJECT_CLASS (shumate_vector_style_parent_class)->finalize (object);
@@ -126,6 +135,60 @@ shumate_vector_style_class_init (ShumateVectorStyleClass *klass)
 }
 
 
+static gboolean
+shumate_vector_style_initable_init (GInitable     *initable,
+                                    GCancellable  *cancellable,
+                                    GError       **error)
+{
+  ShumateVectorStyle *self = (ShumateVectorStyle *)initable;
+  g_autoptr(JsonNode) node = NULL;
+  JsonNode *layers_node;
+  JsonObject *object;
+
+  g_return_val_if_fail (SHUMATE_IS_VECTOR_STYLE (self), FALSE);
+  g_return_val_if_fail (self->style_json != NULL, FALSE);
+
+  if (!(node = json_from_string (self->style_json, error)))
+    return FALSE;
+
+  if (!shumate_vector_json_get_object (node, &object, error))
+    return FALSE;
+
+  self->layers = g_ptr_array_new_with_free_func (g_object_unref);
+  if ((layers_node = json_object_get_member (object, "layers")))
+    {
+      JsonArray *layers;
+
+      if (!shumate_vector_json_get_array (layers_node, &layers, error))
+        return FALSE;
+
+      for (int i = 0, n = json_array_get_length (layers); i < n; i ++)
+        {
+          JsonNode *layer_node = json_array_get_element (layers, i);
+          JsonObject *layer_obj;
+          ShumateVectorLayer *layer;
+
+          if (!shumate_vector_json_get_object (layer_node, &layer_obj, error))
+            return FALSE;
+
+          if (!(layer = shumate_vector_layer_create_from_json (layer_obj, error)))
+            return FALSE;
+
+          g_ptr_array_add (self->layers, layer);
+        }
+    }
+
+  return TRUE;
+}
+
+
+static void
+shumate_vector_style_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = shumate_vector_style_initable_init;
+}
+
+
 static void
 shumate_vector_style_init (ShumateVectorStyle *self)
 {
@@ -195,8 +258,8 @@ shumate_vector_style_render (ShumateVectorStyle *self, int size)
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size);
   cr = cairo_create (surface);
 
-  cairo_set_source_rgb (cr, 0, 0, 0);
-  cairo_paint (cr);
+  for (int i = 0; i < self->layers->len; i ++)
+    shumate_vector_layer_render ((ShumateVectorLayer *)self->layers->pdata[i], cr);
 
   texture = texture_new_for_surface (surface);
 
diff --git a/shumate/shumate-vector-style.h b/shumate/shumate-vector-style.h
index 9249903..48f7d75 100644
--- a/shumate/shumate-vector-style.h
+++ b/shumate/shumate-vector-style.h
@@ -54,7 +54,8 @@ G_DECLARE_FINAL_TYPE (ShumateVectorStyle, shumate_vector_style, SHUMATE, VECTOR_
 
 ShumateVectorStyle *shumate_vector_style_create (const char *style_json, GError **error);
 
+const char *shumate_vector_style_get_style_json (ShumateVectorStyle *self);
+
 GdkTexture *shumate_vector_style_render (ShumateVectorStyle *self, int size);
 
 G_END_DECLS
-
diff --git a/shumate/vector/shumate-vector-background-layer-private.h 
b/shumate/vector/shumate-vector-background-layer-private.h
new file mode 100644
index 0000000..b5dd1ab
--- /dev/null
+++ b/shumate/vector/shumate-vector-background-layer-private.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <json-glib/json-glib.h>
+
+#include "shumate-vector-layer-private.h"
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_BACKGROUND_LAYER (shumate_vector_background_layer_get_type())
+
+G_DECLARE_FINAL_TYPE (ShumateVectorBackgroundLayer, shumate_vector_background_layer, SHUMATE, 
VECTOR_BACKGROUND_LAYER, ShumateVectorLayer)
+
+ShumateVectorLayer *shumate_vector_background_layer_create_from_json (JsonObject *object, GError **error);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-background-layer.c 
b/shumate/vector/shumate-vector-background-layer.c
new file mode 100644
index 0000000..bc427a0
--- /dev/null
+++ b/shumate/vector/shumate-vector-background-layer.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include "shumate-vector-background-layer-private.h"
+#include "shumate-vector-utils-private.h"
+
+struct _ShumateVectorBackgroundLayer
+{
+  ShumateVectorLayer parent_instance;
+
+  GdkRGBA color;
+  double opacity;
+};
+
+G_DEFINE_TYPE (ShumateVectorBackgroundLayer, shumate_vector_background_layer, SHUMATE_TYPE_VECTOR_LAYER)
+
+
+ShumateVectorLayer *
+shumate_vector_background_layer_create_from_json (JsonObject *object, GError **error)
+{
+  ShumateVectorBackgroundLayer *layer = g_object_new (SHUMATE_TYPE_VECTOR_BACKGROUND_LAYER, NULL);
+  JsonNode *paint_node;
+
+  if ((paint_node = json_object_get_member (object, "paint")))
+    {
+      JsonObject *paint;
+
+      if (!shumate_vector_json_get_object (paint_node, &paint, error))
+        return NULL;
+
+      gdk_rgba_parse (&layer->color, json_object_get_string_member_with_default (paint, "background-color", 
"#000000"));
+      layer->opacity = json_object_get_double_member_with_default (paint, "background-opacity", 1.0);
+    }
+
+  return (ShumateVectorLayer *)layer;
+}
+
+
+static void
+shumate_vector_background_layer_render (ShumateVectorLayer *layer, cairo_t *cr)
+{
+  ShumateVectorBackgroundLayer *self = SHUMATE_VECTOR_BACKGROUND_LAYER (layer);
+
+  gdk_cairo_set_source_rgba (cr, &self->color);
+  cairo_paint_with_alpha (cr, self->opacity);
+}
+
+
+static void
+shumate_vector_background_layer_class_init (ShumateVectorBackgroundLayerClass *klass)
+{
+  ShumateVectorLayerClass *layer_class = SHUMATE_VECTOR_LAYER_CLASS (klass);
+
+  layer_class->render = shumate_vector_background_layer_render;
+}
+
+
+static void
+shumate_vector_background_layer_init (ShumateVectorBackgroundLayer *self)
+{
+}
diff --git a/shumate/vector/shumate-vector-layer-private.h b/shumate/vector/shumate-vector-layer-private.h
new file mode 100644
index 0000000..9252bdc
--- /dev/null
+++ b/shumate/vector/shumate-vector-layer-private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include <json-glib/json-glib.h>
+#include <cairo/cairo.h>
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_LAYER (shumate_vector_layer_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (ShumateVectorLayer, shumate_vector_layer, SHUMATE, VECTOR_LAYER, GObject)
+
+struct _ShumateVectorLayerClass
+{
+  GObjectClass parent_class;
+
+  void (*render) (ShumateVectorLayer *self, cairo_t *cr);
+};
+
+ShumateVectorLayer *shumate_vector_layer_create_from_json (JsonObject *object, GError **error);
+
+void shumate_vector_layer_render (ShumateVectorLayer *self, cairo_t *cr);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-layer.c b/shumate/vector/shumate-vector-layer.c
new file mode 100644
index 0000000..89064a2
--- /dev/null
+++ b/shumate/vector/shumate-vector-layer.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <json-glib/json-glib.h>
+#include "shumate-vector-background-layer-private.h"
+#include "shumate-vector-layer-private.h"
+
+typedef struct
+{
+  GObject parent_instance;
+
+  double minzoom;
+  double maxzoom;
+  char *source_layer;
+} ShumateVectorLayerPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (ShumateVectorLayer, shumate_vector_layer, G_TYPE_OBJECT)
+
+
+ShumateVectorLayer *
+shumate_vector_layer_create_from_json (JsonObject *object, GError **error)
+{
+  ShumateVectorLayer *layer;
+  ShumateVectorLayerPrivate *priv;
+  const char *type = json_object_get_string_member_with_default (object, "type", NULL);
+
+  if (type == NULL)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Expected element of \"layer\" to have a string 
member \"type\"");
+      return NULL;
+    }
+
+  if (g_strcmp0 (type, "background") == 0)
+    layer = shumate_vector_background_layer_create_from_json (object, error);
+  else
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unsupported layer type \"%s\"", type);
+      return NULL;
+    }
+
+  if (layer == NULL)
+    /* A problem occurred in one of the constructors above, and error is already
+     * set */
+    return NULL;
+
+  priv = shumate_vector_layer_get_instance_private (layer);
+  priv->minzoom = json_object_get_double_member_with_default (object, "minzoom", 0.0);
+  priv->maxzoom = json_object_get_double_member_with_default (object, "maxzoom", 1000000000.0);
+  priv->source_layer = g_strdup (json_object_get_string_member_with_default (object, "source-layer", NULL));
+
+  return layer;
+}
+
+
+static void
+shumate_vector_layer_finalize (GObject *object)
+{
+  ShumateVectorLayer *self = (ShumateVectorLayer *)object;
+  ShumateVectorLayerPrivate *priv = shumate_vector_layer_get_instance_private (self);
+
+  g_clear_pointer (&priv->source_layer, g_free);
+
+  G_OBJECT_CLASS (shumate_vector_layer_parent_class)->finalize (object);
+}
+
+
+static void
+shumate_vector_layer_class_init (ShumateVectorLayerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ShumateVectorLayerClass *layer_class = SHUMATE_VECTOR_LAYER_CLASS (klass);
+
+  object_class->finalize = shumate_vector_layer_finalize;
+
+  layer_class->render = NULL;
+}
+
+static void
+shumate_vector_layer_init (ShumateVectorLayer *self)
+{
+}
+
+
+/**
+ * shumate_vector_layer_render:
+ * @self: a [class@VectorLayer]
+ *
+ * Renders the layer by calling the [vfunc@VectorLayer.render] virtual method.
+ */
+void
+shumate_vector_layer_render (ShumateVectorLayer *self, cairo_t *cr)
+{
+  g_return_if_fail (SHUMATE_IS_VECTOR_LAYER (self));
+
+  SHUMATE_VECTOR_LAYER_GET_CLASS (self)->render (self, cr);
+}
diff --git a/tests/data/meson.build b/tests/data/meson.build
new file mode 100644
index 0000000..6c31843
--- /dev/null
+++ b/tests/data/meson.build
@@ -0,0 +1,5 @@
+test_resources = gnome.compile_resources(
+  'shumate-test-resources',
+  'tests.gresource.xml',
+  c_name: 'shumate_tests'
+)
diff --git a/tests/data/style.json b/tests/data/style.json
new file mode 100644
index 0000000..af145a4
--- /dev/null
+++ b/tests/data/style.json
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "type": "background",
+      "paint": {
+        "background-color": "goldenrod",
+        "background-opacity": 0.5
+      }
+    }
+  ]
+}
diff --git a/tests/data/tests.gresource.xml b/tests/data/tests.gresource.xml
new file mode 100644
index 0000000..6359a7a
--- /dev/null
+++ b/tests/data/tests.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/shumate/Tests">
+    <file>style.json</file>
+  </gresource>
+</gresources>
diff --git a/tests/meson.build b/tests/meson.build
index 0212112..a12e451 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -14,9 +14,12 @@ tests = [
   'marker-layer',
   'memory-cache',
   'network-tile-source',
+  'vector-style',
   'viewport',
 ]
 
+subdir('data')
+
 test_utils_sources = [
   'test-tile-server.c',
 ]
@@ -34,6 +37,7 @@ testutils_dep = declare_dependency(
 foreach test : tests
   executable = executable(
     test,
+    test_resources,
     '@0@.c'.format(test),
     dependencies: [libshumate_dep, testutils_dep],
   )
diff --git a/tests/vector-style.c b/tests/vector-style.c
new file mode 100644
index 0000000..0739cb3
--- /dev/null
+++ b/tests/vector-style.c
@@ -0,0 +1,26 @@
+#include <gtk/gtk.h>
+#include <shumate/shumate.h>
+
+static void
+test_vector_style_create (void)
+{
+  GError *error = NULL;
+  g_autoptr(GBytes) style_json = NULL;
+  g_autoptr(ShumateVectorStyle) style = NULL;
+
+  style_json = g_resources_lookup_data ("/org/gnome/shumate/Tests/style.json", G_RESOURCE_LOOKUP_FLAGS_NONE, 
NULL);
+  g_assert_no_error (error);
+
+  style = shumate_vector_style_create (g_bytes_get_data (style_json, NULL), &error);
+  g_assert_no_error (error);
+}
+
+int
+main (int argc, char *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/vector-style/create", test_vector_style_create);
+
+  return g_test_run ();
+}


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