Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2021 James Westman <james@jwestman.net>
3 : : *
4 : : * This library is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * This library is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with this library; if not, see <https://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : :
19 : : #include "shumate-data-source.h"
20 : : #include "shumate-raster-renderer.h"
21 : : #include "shumate-tile-downloader.h"
22 : :
23 : :
24 : : struct _ShumateRasterRenderer
25 : : {
26 : : ShumateMapSource parent_instance;
27 : :
28 : : ShumateDataSource *data_source;
29 : : };
30 : :
31 [ + + + - ]: 36 : G_DEFINE_TYPE (ShumateRasterRenderer, shumate_raster_renderer, SHUMATE_TYPE_MAP_SOURCE)
32 : :
33 : : enum {
34 : : PROP_0,
35 : : PROP_DATA_SOURCE,
36 : : N_PROPS
37 : : };
38 : :
39 : : static GParamSpec *properties [N_PROPS];
40 : :
41 : :
42 : : /**
43 : : * shumate_raster_renderer_new:
44 : : * @data_source: a [class@DataSource] to provide tile image data
45 : : *
46 : : * Creates a new [class@RasterRenderer] that uses the given data source.
47 : : *
48 : : * Returns: (transfer full): a newly constructed [class@RasterRenderer]
49 : : */
50 : : ShumateRasterRenderer *
51 : 0 : shumate_raster_renderer_new (ShumateDataSource *data_source)
52 : : {
53 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (data_source), NULL);
54 : 0 : return g_object_new (SHUMATE_TYPE_RASTER_RENDERER,
55 : : "data-source", data_source,
56 : : NULL);
57 : : }
58 : :
59 : : /**
60 : : * shumate_raster_renderer_new_from_url:
61 : : * @url_template: a URL template to fetch tiles from
62 : : *
63 : : * Creates a new [class@RasterRenderer] that fetches tiles from the given URL
64 : : * using a [class@TileDownloader] data source.
65 : : *
66 : : * Equivalent to:
67 : : *
68 : : * ```c
69 : : * g_autoptr(ShumateTileDownloader) source = shumate_tile_downloader_new (url_template);
70 : : * ShumateRasterRenderer *renderer = shumate_raster_renderer_new (source);
71 : : * ```
72 : : *
73 : : * Returns: (transfer full): a newly constructed [class@RasterRenderer]
74 : : */
75 : : ShumateRasterRenderer *
76 : 0 : shumate_raster_renderer_new_from_url (const char *url_template)
77 : : {
78 : 0 : g_autoptr(ShumateDataSource) data_source = NULL;
79 : :
80 [ # # ]: 0 : g_return_val_if_fail (url_template != NULL, NULL);
81 : :
82 : 0 : data_source = SHUMATE_DATA_SOURCE (shumate_tile_downloader_new (url_template));
83 : 0 : return shumate_raster_renderer_new (data_source);
84 : : }
85 : :
86 : :
87 : : /**
88 : : * shumate_raster_renderer_new_full:
89 : : * @id: the map source's id
90 : : * @name: the map source's name
91 : : * @license: the map source's license
92 : : * @license_uri: the map source's license URI
93 : : * @min_zoom: the map source's minimum zoom level
94 : : * @max_zoom: the map source's maximum zoom level
95 : : * @tile_size: the map source's tile size (in pixels)
96 : : * @projection: the map source's projection
97 : : * @data_source: a [class@DataSource] to provide tile image data
98 : : *
99 : : * Creates a new [class@RasterRenderer] with the given details and a data
100 : : * source.
101 : : *
102 : : * Returns: a newly constructed [class@RasterRenderer]
103 : : */
104 : : ShumateRasterRenderer *
105 : 0 : shumate_raster_renderer_new_full (const char *id,
106 : : const char *name,
107 : : const char *license,
108 : : const char *license_uri,
109 : : guint min_zoom,
110 : : guint max_zoom,
111 : : guint tile_size,
112 : : ShumateMapProjection projection,
113 : : ShumateDataSource *data_source)
114 : : {
115 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (data_source), NULL);
116 : :
117 : 0 : return g_object_new (SHUMATE_TYPE_RASTER_RENDERER,
118 : : "id", id,
119 : : "name", name,
120 : : "license", license,
121 : : "license-uri", license_uri,
122 : : "min-zoom-level", min_zoom,
123 : : "max-zoom-level", max_zoom,
124 : : "tile-size", tile_size,
125 : : "projection", projection,
126 : : "data-source", data_source,
127 : : NULL);
128 : : }
129 : :
130 : :
131 : : /**
132 : : * shumate_raster_renderer_new_full_from_url:
133 : : * @id: the map source's id
134 : : * @name: the map source's name
135 : : * @license: the map source's license
136 : : * @license_uri: the map source's license URI
137 : : * @min_zoom: the map source's minimum zoom level
138 : : * @max_zoom: the map source's maximum zoom level
139 : : * @tile_size: the map source's tile size (in pixels)
140 : : * @projection: the map source's projection
141 : : * @url_template: a URL template to fetch tiles from
142 : : *
143 : : * Creates a new [class@RasterRenderer] with the given details and a data
144 : : * source.
145 : : *
146 : : * Returns: a newly constructed [class@RasterRenderer]
147 : : */
148 : : ShumateRasterRenderer *
149 : 27 : shumate_raster_renderer_new_full_from_url (const char *id,
150 : : const char *name,
151 : : const char *license,
152 : : const char *license_uri,
153 : : guint min_zoom,
154 : : guint max_zoom,
155 : : guint tile_size,
156 : : ShumateMapProjection projection,
157 : : const char *url_template)
158 : : {
159 : 54 : g_autoptr(ShumateTileDownloader) data_source = NULL;
160 : :
161 [ + - ]: 27 : g_return_val_if_fail (url_template != NULL, NULL);
162 : :
163 : 27 : data_source = shumate_tile_downloader_new (url_template);
164 : :
165 : 27 : return g_object_new (SHUMATE_TYPE_RASTER_RENDERER,
166 : : "id", id,
167 : : "name", name,
168 : : "license", license,
169 : : "license-uri", license_uri,
170 : : "min-zoom-level", min_zoom,
171 : : "max-zoom-level", max_zoom,
172 : : "tile-size", tile_size,
173 : : "projection", projection,
174 : : "data-source", data_source,
175 : : NULL);
176 : : }
177 : :
178 : : static void
179 : 27 : shumate_raster_renderer_finalize (GObject *object)
180 : : {
181 : 27 : ShumateRasterRenderer *self = (ShumateRasterRenderer *)object;
182 : :
183 [ + - ]: 27 : g_clear_object (&self->data_source);
184 : :
185 : 27 : G_OBJECT_CLASS (shumate_raster_renderer_parent_class)->finalize (object);
186 : 27 : }
187 : :
188 : : static void
189 : 0 : shumate_raster_renderer_get_property (GObject *object,
190 : : guint prop_id,
191 : : GValue *value,
192 : : GParamSpec *pspec)
193 : : {
194 : 0 : ShumateRasterRenderer *self = SHUMATE_RASTER_RENDERER (object);
195 : :
196 [ # # ]: 0 : switch (prop_id)
197 : : {
198 : 0 : case PROP_DATA_SOURCE:
199 : 0 : g_value_set_object (value, self->data_source);
200 : 0 : break;
201 : 0 : default:
202 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203 : : }
204 : 0 : }
205 : :
206 : : static void
207 : 27 : shumate_raster_renderer_set_property (GObject *object,
208 : : guint prop_id,
209 : : const GValue *value,
210 : : GParamSpec *pspec)
211 : : {
212 : 27 : ShumateRasterRenderer *self = SHUMATE_RASTER_RENDERER (object);
213 : :
214 [ + - ]: 27 : switch (prop_id)
215 : : {
216 : 27 : case PROP_DATA_SOURCE:
217 : 27 : g_set_object (&self->data_source, g_value_get_object (value));
218 : 27 : break;
219 : 0 : default:
220 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
221 : : }
222 : 27 : }
223 : :
224 : : static void shumate_raster_renderer_fill_tile_async (ShumateMapSource *map_source,
225 : : ShumateTile *tile,
226 : : GCancellable *cancellable,
227 : : GAsyncReadyCallback callback,
228 : : gpointer user_data);
229 : :
230 : : static gboolean shumate_raster_renderer_fill_tile_finish (ShumateMapSource *map_source,
231 : : GAsyncResult *result,
232 : : GError **error);
233 : :
234 : : static void
235 : 4 : shumate_raster_renderer_class_init (ShumateRasterRendererClass *klass)
236 : : {
237 : 4 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
238 : 4 : ShumateMapSourceClass *map_source_class = SHUMATE_MAP_SOURCE_CLASS (klass);
239 : :
240 : 4 : object_class->finalize = shumate_raster_renderer_finalize;
241 : 4 : object_class->get_property = shumate_raster_renderer_get_property;
242 : 4 : object_class->set_property = shumate_raster_renderer_set_property;
243 : :
244 : 4 : map_source_class->fill_tile_async = shumate_raster_renderer_fill_tile_async;
245 : 4 : map_source_class->fill_tile_finish = shumate_raster_renderer_fill_tile_finish;
246 : :
247 : : /**
248 : : * ShumateRasterRenderer:data-source:
249 : : *
250 : : * The data source that provides image tiles to display. In most cases,
251 : : * a [class@TileDownloader] is sufficient.
252 : : */
253 : 8 : properties[PROP_DATA_SOURCE] =
254 : 4 : g_param_spec_object ("data-source",
255 : : "Data source",
256 : : "Data source",
257 : : SHUMATE_TYPE_DATA_SOURCE,
258 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
259 : :
260 : 4 : g_object_class_install_properties (object_class, N_PROPS, properties);
261 : 4 : }
262 : :
263 : : static void
264 : 27 : shumate_raster_renderer_init (ShumateRasterRenderer *self)
265 : : {
266 : 27 : }
267 : :
268 : :
269 : : static void
270 : 0 : on_request_notify (ShumateDataSourceRequest *req,
271 : : GParamSpec *pspec,
272 : : gpointer user_data)
273 : : {
274 : 0 : GTask *task = user_data;
275 : 0 : GBytes *data;
276 : 0 : ShumateTile *tile = g_task_get_task_data (task);
277 : :
278 [ # # ]: 0 : if ((data = shumate_data_source_request_get_data (req)))
279 : : {
280 : 0 : g_autoptr(GError) error = NULL;
281 [ # # # # ]: 0 : g_autoptr(GdkPixbuf) pixbuf = NULL;
282 [ # # # # ]: 0 : g_autoptr(GInputStream) stream = NULL;
283 [ # # # # ]: 0 : g_autoptr(GdkTexture) texture = NULL;
284 : :
285 : 0 : stream = g_memory_input_stream_new_from_bytes (data);
286 : 0 : pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
287 [ # # ]: 0 : if (error)
288 : : {
289 : 0 : g_warning ("Failed to create texture from tile data (%d, %d @ %d): %s",
290 : : shumate_tile_get_x (tile),
291 : : shumate_tile_get_y (tile),
292 : : shumate_tile_get_zoom_level (tile),
293 : : error->message);
294 [ # # ]: 0 : return;
295 : : }
296 : :
297 : 0 : texture = gdk_texture_new_for_pixbuf (pixbuf);
298 [ # # ]: 0 : shumate_tile_set_paintable (tile, GDK_PAINTABLE (texture));
299 : : }
300 : : }
301 : :
302 : : static void
303 : 0 : on_request_notify_completed (ShumateDataSourceRequest *req,
304 : : GParamSpec *pspec,
305 : : gpointer user_data)
306 : : {
307 : 0 : g_autoptr(GTask) task = user_data;
308 : 0 : GError *error;
309 : 0 : ShumateTile *tile = g_task_get_task_data (task);
310 : :
311 : 0 : shumate_tile_set_state (tile, SHUMATE_STATE_DONE);
312 : :
313 [ # # ]: 0 : if ((error = shumate_data_source_request_get_error (req)))
314 : 0 : g_task_return_error (task, g_error_copy (error));
315 : : else
316 : 0 : g_task_return_boolean (task, TRUE);
317 : 0 : }
318 : :
319 : : static void
320 : 0 : shumate_raster_renderer_fill_tile_async (ShumateMapSource *map_source,
321 : : ShumateTile *tile,
322 : : GCancellable *cancellable,
323 : : GAsyncReadyCallback callback,
324 : : gpointer user_data)
325 : : {
326 : 0 : ShumateRasterRenderer *self = (ShumateRasterRenderer *)map_source;
327 : 0 : g_autoptr(GTask) task = NULL;
328 [ # # ]: 0 : g_autoptr(ShumateDataSourceRequest) req = NULL;
329 : :
330 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_RASTER_RENDERER (self));
331 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_TILE (tile));
332 [ # # # # : 0 : g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
# # # # ]
333 : :
334 : 0 : task = g_task_new (self, cancellable, callback, user_data);
335 [ # # ]: 0 : g_task_set_source_tag (task, shumate_raster_renderer_fill_tile_async);
336 : :
337 : 0 : g_task_set_task_data (task, g_object_ref (tile), (GDestroyNotify)g_object_unref);
338 : :
339 : 0 : req = shumate_data_source_start_request (self->data_source,
340 : 0 : shumate_tile_get_x (tile),
341 : 0 : shumate_tile_get_y (tile),
342 : 0 : shumate_tile_get_zoom_level (tile),
343 : : cancellable);
344 : :
345 [ # # ]: 0 : if (shumate_data_source_request_is_completed (req))
346 : : {
347 : 0 : on_request_notify (req, NULL, task);
348 : 0 : on_request_notify_completed (req, NULL, g_steal_pointer (&task));
349 : : }
350 : : else
351 : : {
352 : 0 : g_signal_connect_object (req, "notify::data", (GCallback)on_request_notify, task, 0);
353 : 0 : g_signal_connect_object (req, "notify::completed", (GCallback)on_request_notify_completed, g_object_ref (task), 0);
354 : : }
355 : : }
356 : :
357 : : static gboolean
358 : 0 : shumate_raster_renderer_fill_tile_finish (ShumateMapSource *map_source,
359 : : GAsyncResult *result,
360 : : GError **error)
361 : : {
362 : 0 : ShumateRasterRenderer *self = (ShumateRasterRenderer *)map_source;
363 : :
364 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_RASTER_RENDERER (self), FALSE);
365 [ # # ]: 0 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
366 : :
367 : 0 : return g_task_propagate_boolean (G_TASK (result), error);
368 : : }
|