GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 32.4% 34 / 0 / 105
Functions: 50.0% 8 / 0 / 16
Branches: 10.9% 7 / 0 / 64

shumate/shumate-raster-renderer.c
Line Branch Exec Source
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
4/6
shumate_raster_renderer_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
shumate_raster_renderer_get_type:
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 7 taken 16 times.
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 7 not taken.
25 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 ✗ shumate_raster_renderer_new (ShumateDataSource *data_source)
52 {
53 ✗ g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (data_source), NULL);
54 ✗ 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 ✗ shumate_raster_renderer_new_from_url (const char *url_template)
77 {
78 ✗ g_autoptr(ShumateDataSource) data_source = NULL;
79
80 ✗ g_return_val_if_fail (url_template != NULL, NULL);
81
82 ✗ data_source = SHUMATE_DATA_SOURCE (shumate_tile_downloader_new (url_template));
83 ✗ 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 ✗ 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 ✗ g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (data_source), NULL);
116
117 ✗ 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 18 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 36 g_autoptr(ShumateTileDownloader) data_source = NULL;
160
161
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 18 times.
18 g_return_val_if_fail (url_template != NULL, NULL);
162
163 18 data_source = shumate_tile_downloader_new (url_template);
164
165 18 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 18 shumate_raster_renderer_finalize (GObject *object)
180 {
181 18 ShumateRasterRenderer *self = (ShumateRasterRenderer *)object;
182
183
1/2
✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 4 not taken.
18 g_clear_object (&self->data_source);
184
185 18 G_OBJECT_CLASS (shumate_raster_renderer_parent_class)->finalize (object);
186 18 }
187
188 static void
189 ✗ shumate_raster_renderer_get_property (GObject *object,
190 guint prop_id,
191 GValue *value,
192 GParamSpec *pspec)
193 {
194 ✗ ShumateRasterRenderer *self = SHUMATE_RASTER_RENDERER (object);
195
196 ✗ switch (prop_id)
197 {
198 ✗ case PROP_DATA_SOURCE:
199 ✗ g_value_set_object (value, self->data_source);
200 ✗ break;
201 ✗ default:
202 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203 }
204 ✗ }
205
206 static void
207 18 shumate_raster_renderer_set_property (GObject *object,
208 guint prop_id,
209 const GValue *value,
210 GParamSpec *pspec)
211 {
212 18 ShumateRasterRenderer *self = SHUMATE_RASTER_RENDERER (object);
213
214
1/2
✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 6 not taken.
18 switch (prop_id)
215 {
216 18 case PROP_DATA_SOURCE:
217 18 g_set_object (&self->data_source, g_value_get_object (value));
218 18 break;
219 ✗ default:
220 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
221 }
222 18 }
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 3 shumate_raster_renderer_class_init (ShumateRasterRendererClass *klass)
236 {
237 3 GObjectClass *object_class = G_OBJECT_CLASS (klass);
238 3 ShumateMapSourceClass *map_source_class = SHUMATE_MAP_SOURCE_CLASS (klass);
239
240 3 object_class->finalize = shumate_raster_renderer_finalize;
241 3 object_class->get_property = shumate_raster_renderer_get_property;
242 3 object_class->set_property = shumate_raster_renderer_set_property;
243
244 3 map_source_class->fill_tile_async = shumate_raster_renderer_fill_tile_async;
245 3 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 6 properties[PROP_DATA_SOURCE] =
254 3 g_param_spec_object ("data-source", NULL, NULL,
255 SHUMATE_TYPE_DATA_SOURCE,
256 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
257
258 3 g_object_class_install_properties (object_class, N_PROPS, properties);
259 3 }
260
261 static void
262 18 shumate_raster_renderer_init (ShumateRasterRenderer *self)
263 {
264 18 }
265
266
267 static void
268 ✗ on_request_notify (ShumateDataSourceRequest *req,
269 GParamSpec *pspec,
270 gpointer user_data)
271 {
272 ✗ GTask *task = user_data;
273 ✗ GBytes *data;
274 ✗ ShumateTile *tile = g_task_get_task_data (task);
275
276 ✗ if ((data = shumate_data_source_request_get_data (req)))
277 {
278 ✗ g_autoptr(GError) error = NULL;
279 ✗ g_autoptr(GdkPixbuf) pixbuf = NULL;
280 ✗ g_autoptr(GInputStream) stream = NULL;
281 ✗ g_autoptr(GdkTexture) texture = NULL;
282
283 ✗ stream = g_memory_input_stream_new_from_bytes (data);
284 ✗ pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
285 ✗ if (error)
286 {
287 ✗ g_warning ("Failed to create texture from tile data (%d, %d @ %d): %s",
288 shumate_tile_get_x (tile),
289 shumate_tile_get_y (tile),
290 shumate_tile_get_zoom_level (tile),
291 error->message);
292 ✗ return;
293 }
294
295 ✗ texture = gdk_texture_new_for_pixbuf (pixbuf);
296 ✗ shumate_tile_set_paintable (tile, GDK_PAINTABLE (texture));
297 }
298 }
299
300 static void
301 ✗ on_request_notify_completed (ShumateDataSourceRequest *req,
302 GParamSpec *pspec,
303 gpointer user_data)
304 {
305 ✗ g_autoptr(GTask) task = user_data;
306 ✗ GError *error;
307 ✗ ShumateTile *tile = g_task_get_task_data (task);
308
309 ✗ shumate_tile_set_state (tile, SHUMATE_STATE_DONE);
310
311 ✗ if ((error = shumate_data_source_request_get_error (req)))
312 ✗ g_task_return_error (task, g_error_copy (error));
313 else
314 ✗ g_task_return_boolean (task, TRUE);
315 ✗ }
316
317 static void
318 ✗ shumate_raster_renderer_fill_tile_async (ShumateMapSource *map_source,
319 ShumateTile *tile,
320 GCancellable *cancellable,
321 GAsyncReadyCallback callback,
322 gpointer user_data)
323 {
324 ✗ ShumateRasterRenderer *self = (ShumateRasterRenderer *)map_source;
325 ✗ g_autoptr(GTask) task = NULL;
326 ✗ g_autoptr(ShumateDataSourceRequest) req = NULL;
327
328 ✗ g_return_if_fail (SHUMATE_IS_RASTER_RENDERER (self));
329 ✗ g_return_if_fail (SHUMATE_IS_TILE (tile));
330 ✗ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
331
332 ✗ task = g_task_new (self, cancellable, callback, user_data);
333 ✗ g_task_set_source_tag (task, shumate_raster_renderer_fill_tile_async);
334
335 ✗ g_task_set_task_data (task, g_object_ref (tile), (GDestroyNotify)g_object_unref);
336
337 ✗ req = shumate_data_source_start_request (self->data_source,
338 ✗ shumate_tile_get_x (tile),
339 ✗ shumate_tile_get_y (tile),
340 ✗ shumate_tile_get_zoom_level (tile),
341 cancellable);
342
343 ✗ if (shumate_data_source_request_is_completed (req))
344 {
345 ✗ on_request_notify (req, NULL, task);
346 ✗ on_request_notify_completed (req, NULL, g_steal_pointer (&task));
347 }
348 else
349 {
350 ✗ g_signal_connect_object (req, "notify::data", (GCallback)on_request_notify, task, 0);
351 ✗ g_signal_connect_object (req, "notify::completed", (GCallback)on_request_notify_completed, g_object_ref (task), 0);
352 }
353 }
354
355 static gboolean
356 ✗ shumate_raster_renderer_fill_tile_finish (ShumateMapSource *map_source,
357 GAsyncResult *result,
358 GError **error)
359 {
360 ✗ ShumateRasterRenderer *self = (ShumateRasterRenderer *)map_source;
361
362 ✗ g_return_val_if_fail (SHUMATE_IS_RASTER_RENDERER (self), FALSE);
363 ✗ g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
364
365 ✗ return g_task_propagate_boolean (G_TASK (result), error);
366 }
367