1 /*
2  * Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of ZToolkit
5  *
6  * ZToolkit is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * ZToolkit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Affero Public License
17  * along with ZToolkit.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "ztoolkit_config.h"
21 
22 #ifdef HAVE_RSVG
23 
24 #include <ztoolkit/ztk.h>
25 
26 #include <librsvg/rsvg.h>
27 
28 /**
29  * Loads an SVG from an absolute path.
30  *
31  * @return An rsvg handle, or NULL if failed.
32  */
33 ZtkRsvgHandle *
ztk_rsvg_load_svg(const char * abs_path)34 ztk_rsvg_load_svg (
35   const char * abs_path)
36 {
37   GFile * file =
38     g_file_new_for_path (abs_path);
39   GError * err = NULL;
40   RsvgHandle * handle =
41     rsvg_handle_new_from_gfile_sync (
42       file, RSVG_HANDLE_FLAGS_NONE, NULL, &err);
43   if (err)
44     {
45       ztk_error (
46         "An error occurred parsing the SVG file at "
47         "%s: %s", abs_path, err->message);
48       g_object_unref (file);
49       return NULL;
50     }
51   g_object_unref (file);
52 
53   /* common values are 75, 90, 300 */
54   rsvg_handle_set_dpi (handle, 300);
55 
56   return (ZtkRsvgHandle *) handle;
57 }
58 
59 /**
60  * Gets the width of the svg.
61  */
62 int
ztk_rsvg_get_width(ZtkRsvgHandle * handle)63 ztk_rsvg_get_width (
64   ZtkRsvgHandle * handle)
65 {
66   RsvgDimensionData dim;
67   rsvg_handle_get_dimensions (
68     (RsvgHandle *) handle, &dim);
69   return dim.width;
70 }
71 
72 /**
73  * Gets the height of the svg.
74  */
75 int
ztk_rsvg_get_height(ZtkRsvgHandle * handle)76 ztk_rsvg_get_height (
77   ZtkRsvgHandle * handle)
78 {
79   RsvgDimensionData dim;
80   rsvg_handle_get_dimensions (
81     (RsvgHandle *) handle, &dim);
82   return dim.height;
83 }
84 
85 /**
86  * Draws the SVG on the current cairo context.
87  *
88  * @return 0 if successful, non-zero if failed.
89  */
90 int
ztk_rsvg_draw(ZtkRsvgHandle * handle,cairo_t * cr,ZtkRect * rect)91 ztk_rsvg_draw (
92   ZtkRsvgHandle * handle,
93   cairo_t *       cr,
94   ZtkRect *       rect)
95 {
96 #ifdef HAVE_RSVG_2_46
97   RsvgRectangle viewport = {
98     rect->x, rect->y, rect->width, rect->height };
99   GError * err = NULL;
100   rsvg_handle_render_document (
101     (RsvgHandle *) handle, cr, &viewport, &err);
102   if (err)
103     {
104       return -1;
105     }
106 #else
107   int rwidth =
108     ztk_rsvg_get_width (handle);
109   int rheight =
110     ztk_rsvg_get_height (handle);
111   double xscale =
112     (double) rect->width / (double) rwidth ;
113   double yscale =
114     (double) rect->height / (double) rheight;
115   double scale = MIN (xscale, yscale);
116   double leftover_x =
117     rect->width - scale * rwidth;
118   double leftover_y =
119     rect->height - scale * rheight;
120   cairo_save (cr);
121   cairo_translate (cr, rect->x + leftover_x / 2, rect->y + leftover_y / 2);
122   cairo_scale (
123     cr, scale, scale);
124   rsvg_handle_render_cairo (
125     (RsvgHandle *) handle, cr);
126   cairo_restore (cr);
127 #endif
128 
129   return 0;
130 }
131 
132 #endif // HAVE_RSVG
133