GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 52.5% 73 / 0 / 139
Functions: 60.9% 14 / 0 / 23
Branches: 32.0% 16 / 0 / 50

shumate/shumate-vector-sprite.c
Line Branch Exec Source
1 /*
2 * Copyright (C) 2023 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 #include <gtk/gtk.h>
19
20 #include "shumate-vector-sprite.h"
21
22 /**
23 * ShumateVectorSprite:
24 *
25 * A sprite used to draw textures or icons.
26 *
27 * ## Symbolic icons
28 *
29 * If a sprite is created from a [iface@Gtk.SymbolicPaintable] source, such
30 * as a symbolic icon, then when the sprite is part of a symbol layer it
31 * will be drawn using the icon-color property (or the text color, if the
32 * sprite is part of a formatted string).
33 *
34 * Since: 1.1
35 */
36
37
38 struct _ShumateVectorSprite
39 {
40 GObject parent_instance;
41
42 GdkPaintable *source_paintable;
43 int width, height;
44 double scale_factor;
45
46 GdkRectangle source_rect;
47 gboolean source_rect_set : 1;
48 };
49
50 static void shumate_vector_sprite_paintable_iface_init (GdkPaintableInterface *iface);
51 static void shumate_vector_sprite_symbolic_paintable_iface_init (GtkSymbolicPaintableInterface *iface);
52
53
4/6
shumate_vector_sprite_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
shumate_vector_sprite_get_type:
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 7 taken 496 times.
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 7 not taken.
511 G_DEFINE_TYPE_WITH_CODE (ShumateVectorSprite, shumate_vector_sprite, G_TYPE_OBJECT,
54 G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, shumate_vector_sprite_paintable_iface_init)
55 G_IMPLEMENT_INTERFACE (GTK_TYPE_SYMBOLIC_PAINTABLE, shumate_vector_sprite_symbolic_paintable_iface_init))
56
57 enum {
58 PROP_0,
59 PROP_WIDTH,
60 PROP_HEIGHT,
61 PROP_SCALE_FACTOR,
62 PROP_SOURCE_PAINTABLE,
63 PROP_SOURCE_RECT,
64 N_PROPERTIES
65 };
66
67 static GParamSpec *properties[N_PROPERTIES];
68
69 /**
70 * shumate_vector_sprite_new:
71 * @source_paintable: a [iface@Gdk.Paintable]
72 *
73 * Creates a new [class@VectorSprite] using the paintable's intrinsic size.
74 *
75 * Since: 1.1
76 */
77 ShumateVectorSprite *
78 206 shumate_vector_sprite_new (GdkPaintable *source_paintable)
79 {
80 206 return g_object_new (SHUMATE_TYPE_VECTOR_SPRITE,
81 "source-paintable", source_paintable,
82 "width", gdk_paintable_get_intrinsic_width (source_paintable),
83 "height", gdk_paintable_get_intrinsic_height (source_paintable),
84 NULL);
85 }
86
87 /**
88 * shumate_vector_sprite_new_full:
89 * @source_paintable: a [iface@Gdk.Paintable]
90 * @width: the width of the sprite in pixels
91 * @height: the height of the sprite in pixels
92 * @scale_factor: the intended scale factor of the sprite
93 * @source_rect: (nullable): the source rectangle of the sprite, or %NULL to use the entire paintable
94 *
95 * Creates a new [class@VectorSprite] with the given size, scale factor,
96 * and area of the source paintable.
97 *
98 * Since: 1.1
99 */
100 ShumateVectorSprite *
101 10 shumate_vector_sprite_new_full (GdkPaintable *source_paintable,
102 int width,
103 int height,
104 double scale_factor,
105 GdkRectangle *source_rect)
106 {
107 10 return g_object_new (SHUMATE_TYPE_VECTOR_SPRITE,
108 "source-paintable", source_paintable,
109 "width", width,
110 "height", height,
111 "scale-factor", scale_factor,
112 "source-rect", source_rect,
113 NULL);
114 }
115
116 static void
117 216 shumate_vector_sprite_finalize (GObject *object)
118 {
119 216 ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (object);
120
121
1/2
✓ Branch 2 → 3 taken 216 times.
✗ Branch 2 → 4 not taken.
216 g_clear_object (&self->source_paintable);
122
123 216 G_OBJECT_CLASS (shumate_vector_sprite_parent_class)->finalize (object);
124 216 }
125
126 static void
127 ✗ shumate_vector_sprite_get_property (GObject *object,
128 unsigned prop_id,
129 GValue *value,
130 GParamSpec *pspec)
131 {
132 ✗ ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (object);
133
134 ✗ switch (prop_id)
135 {
136 ✗ case PROP_WIDTH:
137 ✗ g_value_set_int (value, self->width);
138 ✗ break;
139 ✗ case PROP_HEIGHT:
140 ✗ g_value_set_int (value, self->height);
141 ✗ break;
142 ✗ case PROP_SCALE_FACTOR:
143 ✗ g_value_set_double (value, self->scale_factor);
144 ✗ break;
145 ✗ case PROP_SOURCE_PAINTABLE:
146 ✗ g_value_set_object (value, self->source_paintable);
147 ✗ break;
148 ✗ case PROP_SOURCE_RECT:
149 ✗ if (self->source_rect_set)
150 ✗ g_value_set_boxed (value, &self->source_rect);
151 else
152 ✗ g_value_set_boxed (value, NULL);
153 break;
154 ✗ default:
155 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
156 }
157 ✗ }
158
159 static void
160 1080 shumate_vector_sprite_set_property (GObject *object,
161 unsigned prop_id,
162 const GValue *value,
163 GParamSpec *pspec)
164 {
165 1080 ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (object);
166
167
5/6
✓ Branch 2 → 3 taken 216 times.
✓ Branch 2 → 5 taken 216 times.
✓ Branch 2 → 7 taken 216 times.
✓ Branch 2 → 9 taken 216 times.
✓ Branch 2 → 13 taken 216 times.
✗ Branch 2 → 17 not taken.
1080 switch (prop_id)
168 {
169 216 case PROP_WIDTH:
170 216 self->width = g_value_get_int (value);
171 216 break;
172 216 case PROP_HEIGHT:
173 216 self->height = g_value_get_int (value);
174 216 break;
175 216 case PROP_SCALE_FACTOR:
176 216 self->scale_factor = g_value_get_double (value);
177 216 break;
178 216 case PROP_SOURCE_PAINTABLE:
179
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 216 times.
216 g_assert (self->source_paintable == NULL);
180 216 self->source_paintable = g_value_dup_object (value);
181 216 break;
182 216 case PROP_SOURCE_RECT:
183 {
184 216 GdkRectangle *source_rect = (GdkRectangle *) g_value_get_boxed (value);
185
2/2
✓ Branch 14 → 15 taken 10 times.
✓ Branch 14 → 16 taken 206 times.
216 if (source_rect)
186 {
187 10 self->source_rect = *source_rect;
188 10 self->source_rect_set = TRUE;
189 }
190 else
191 206 self->source_rect_set = FALSE;
192 }
193 break;
194 ✗ default:
195 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
196 }
197 1080 }
198
199 static GdkPaintable *
200 ✗ shumate_vector_sprite_get_current_image (GdkPaintable *paintable)
201 {
202 ✗ ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (paintable);
203 ✗ g_autoptr(GdkPaintable) source_paintable = gdk_paintable_get_current_image (self->source_paintable);
204
205 ✗ return GDK_PAINTABLE (shumate_vector_sprite_new_full (
206 source_paintable,
207 self->width,
208 self->height,
209 self->scale_factor,
210 ✗ self->source_rect_set ? &self->source_rect : NULL
211 ));
212 }
213
214 static int
215 ✗ shumate_vector_sprite_get_intrinsic_width (GdkPaintable *paintable)
216 {
217 ✗ ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (paintable);
218 ✗ return self->width;
219 }
220
221 static int
222 ✗ shumate_vector_sprite_get_intrinsic_height (GdkPaintable *paintable)
223 {
224 ✗ ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (paintable);
225 ✗ return self->height;
226 }
227
228 static void
229 ✗ do_snapshot (GdkPaintable *paintable,
230 GdkSnapshot *snapshot,
231 double width,
232 double height,
233 gboolean symbolic,
234 const GdkRGBA *colors,
235 gsize n_colors)
236 {
237 ✗ ShumateVectorSprite *self = SHUMATE_VECTOR_SPRITE (paintable);
238
239 ✗ if (self->source_rect_set)
240 {
241 ✗ double paintable_width = gdk_paintable_get_intrinsic_width (self->source_paintable);
242 ✗ double paintable_height = gdk_paintable_get_intrinsic_height (self->source_paintable);
243
244 ✗ gtk_snapshot_save (snapshot);
245 ✗ gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
246
247 ✗ gtk_snapshot_translate (snapshot,
248 ✗ &GRAPHENE_POINT_INIT (
249 -self->source_rect.x * (width / self->source_rect.width),
250 -self->source_rect.y * (height / self->source_rect.height)
251 ));
252
253 ✗ width = paintable_width * (width / self->source_rect.width);
254 ✗ height = paintable_height * (height / self->source_rect.height);
255 }
256
257 ✗ if (symbolic && GTK_IS_SYMBOLIC_PAINTABLE (self->source_paintable))
258 ✗ gtk_symbolic_paintable_snapshot_symbolic (GTK_SYMBOLIC_PAINTABLE (self->source_paintable),
259 snapshot,
260 width,
261 height,
262 colors,
263 n_colors);
264 else
265 ✗ gdk_paintable_snapshot (self->source_paintable,
266 snapshot,
267 width,
268 height);
269
270 ✗ if (self->source_rect_set)
271 {
272 ✗ gtk_snapshot_pop (snapshot);
273 ✗ gtk_snapshot_restore (snapshot);
274 }
275 ✗ }
276
277 static void
278 ✗ shumate_vector_sprite_snapshot_symbolic (GtkSymbolicPaintable *paintable,
279 GdkSnapshot *snapshot,
280 double width,
281 double height,
282 const GdkRGBA *colors,
283 gsize n_colors)
284 {
285 ✗ do_snapshot (GDK_PAINTABLE (paintable), snapshot, width, height, TRUE, colors, n_colors);
286 ✗ }
287
288 static void
289 ✗ shumate_vector_sprite_snapshot (GdkPaintable *paintable,
290 GdkSnapshot *snapshot,
291 double width,
292 double height)
293 {
294 ✗ do_snapshot (GDK_PAINTABLE (paintable), snapshot, width, height, FALSE, NULL, 0);
295 ✗ }
296
297 static void
298 5 shumate_vector_sprite_class_init (ShumateVectorSpriteClass *klass)
299 {
300 5 GObjectClass *object_class = G_OBJECT_CLASS (klass);
301
302 5 object_class->finalize = shumate_vector_sprite_finalize;
303 5 object_class->get_property = shumate_vector_sprite_get_property;
304 5 object_class->set_property = shumate_vector_sprite_set_property;
305
306 /**
307 * ShumateVectorSprite:source-paintable:
308 *
309 * The [iface@Gdk.Paintable] used to draw the sprite.
310 *
311 * Since: 1.1
312 */
313 10 properties[PROP_SOURCE_PAINTABLE] =
314 5 g_param_spec_object ("source-paintable", NULL, NULL,
315 GDK_TYPE_PAINTABLE,
316 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
317
318 /**
319 * ShumateVectorSprite:width:
320 *
321 * The width at which the sprite should be drawn, in pixels.
322 *
323 * Since: 1.1
324 */
325 10 properties[PROP_WIDTH] =
326 5 g_param_spec_int ("width", NULL, NULL,
327 0, G_MAXINT, 0,
328 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
329
330 /**
331 * ShumateVectorSprite:height:
332 *
333 * The height at which the sprite should be drawn, in pixels.
334 *
335 * Since: 1.1
336 */
337 10 properties[PROP_HEIGHT] =
338 5 g_param_spec_int ("height", NULL, NULL,
339 0, G_MAXINT, 0,
340 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
341
342 /**
343 * ShumateVectorSprite:scale-factor:
344 *
345 * The intended scale factor of the sprite.
346 *
347 * Since: 1.1
348 */
349 10 properties[PROP_SCALE_FACTOR] =
350 5 g_param_spec_double ("scale-factor", NULL, NULL,
351 1, G_MAXDOUBLE, 1,
352 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
353
354 /**
355 * ShumateVectorSprite:source-rect:
356 *
357 * The area of the source rectangle to draw, or %NULL to use the entire paintable.
358 *
359 * Since: 1.1
360 */
361 10 properties[PROP_SOURCE_RECT] =
362 5 g_param_spec_boxed ("source-rect", NULL, NULL,
363 GDK_TYPE_RECTANGLE,
364 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
365
366 5 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
367 5 }
368
369 static void
370 216 shumate_vector_sprite_init (ShumateVectorSprite *self)
371 {
372 216 self->scale_factor = 1;
373 216 }
374
375 static void
376 5 shumate_vector_sprite_paintable_iface_init (GdkPaintableInterface *iface)
377 {
378 5 iface->get_current_image = shumate_vector_sprite_get_current_image;
379 5 iface->get_intrinsic_width = shumate_vector_sprite_get_intrinsic_width;
380 5 iface->get_intrinsic_height = shumate_vector_sprite_get_intrinsic_height;
381 5 iface->snapshot = shumate_vector_sprite_snapshot;
382 5 }
383
384 static void
385 5 shumate_vector_sprite_symbolic_paintable_iface_init (GtkSymbolicPaintableInterface *iface)
386 {
387 5 iface->snapshot_symbolic = shumate_vector_sprite_snapshot_symbolic;
388 5 }
389
390 /**
391 * shumate_vector_sprite_get_source_paintable:
392 * @self: a [class@VectorSprite]
393 *
394 * Gets the source [iface@Gdk.Paintable] used to draw the sprite.
395 *
396 * Note that [class@VectorSprite] also implements [iface@Gdk.Paintable].
397 * In most cases, you should draw the sprite rather than the original paintable.
398 *
399 * Returns: (transfer none): the source paintable
400 *
401 * Since: 1.1
402 */
403 GdkPaintable *
404 4 shumate_vector_sprite_get_source_paintable (ShumateVectorSprite *self)
405 {
406
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 g_return_val_if_fail (SHUMATE_IS_VECTOR_SPRITE (self), NULL);
407
408 4 return self->source_paintable;
409 }
410
411 /**
412 * shumate_vector_sprite_get_width:
413 * @self: a [class@VectorSprite]
414 *
415 * Gets the width at which the sprite should be drawn.
416 *
417 * Returns: the sprite's width in pixels
418 *
419 * Since: 1.1
420 */
421 int
422 4 shumate_vector_sprite_get_width (ShumateVectorSprite *self)
423 {
424
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 g_return_val_if_fail (SHUMATE_IS_VECTOR_SPRITE (self), 0);
425
426 4 return self->width;
427 }
428
429 /**
430 * shumate_vector_sprite_get_height:
431 * @self: a [class@VectorSprite]
432 *
433 * Gets the height at which the sprite should be drawn.
434 *
435 * Returns: the sprite's height in pixels
436 *
437 * Since: 1.1
438 */
439 int
440 ✗ shumate_vector_sprite_get_height (ShumateVectorSprite *self)
441 {
442 ✗ g_return_val_if_fail (SHUMATE_IS_VECTOR_SPRITE (self), 0);
443
444 ✗ return self->height;
445 }
446
447 /**
448 * shumate_vector_sprite_get_scale_factor:
449 * @self: a [class@VectorSprite]
450 *
451 * Gets the intended scale factor of the sprite.
452 *
453 * Returns: the sprite's scale factor
454 *
455 * Since: 1.1
456 */
457 double
458 248 shumate_vector_sprite_get_scale_factor (ShumateVectorSprite *self)
459 {
460
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 248 times.
248 g_return_val_if_fail (SHUMATE_IS_VECTOR_SPRITE (self), 0);
461
462 248 return self->scale_factor;
463 }
464
465 /**
466 * shumate_vector_sprite_get_source_rect:
467 * @self: a [class@VectorSprite]
468 *
469 * Gets the source rectangle of the sprite.
470 *
471 * Returns: (nullable) (transfer none): the sprite's source rectangle, or %NULL if the entire paintable is used
472 *
473 * Since: 1.1
474 */
475 GdkRectangle *
476 ✗ shumate_vector_sprite_get_source_rect (ShumateVectorSprite *self)
477 {
478 ✗ g_return_val_if_fail (SHUMATE_IS_VECTOR_SPRITE (self), NULL);
479
480 ✗ if (self->source_rect_set)
481 ✗ return &self->source_rect;
482 else
483 return NULL;
484 }
485