File: | content/handlers/image/rsvg246.c |
Warning: | line 133, column 2 Value stored to 'renderres' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright 2022 Vincent Sanders <vince@netsurf-browser.org> |
3 | * |
4 | * This file is part of NetSurf, http://www.netsurf-browser.org/ |
5 | * |
6 | * NetSurf is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; version 2 of the License. |
9 | * |
10 | * NetSurf is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | /** |
20 | * \file |
21 | * implementation of content handler for image/svg using librsvg 2.46 API. |
22 | * |
23 | * SVG files are rendered to a NetSurf bitmap by creating a Cairo rendering |
24 | * surface (content_rsvg_data.cs) over the bitmap's data, creating a Cairo |
25 | * drawing context using that surface, and then passing that drawing context |
26 | * to librsvg which then uses Cairo calls to plot the graphic to the bitmap. |
27 | * We store this in content->bitmap, and then use the usual bitmap plotter |
28 | * function to render it for redraw requests. |
29 | */ |
30 | |
31 | #include <stdlib.h> |
32 | #include <stdbool.h> |
33 | #include <assert.h> |
34 | #include <string.h> |
35 | #include <sys/types.h> |
36 | |
37 | #include <librsvg/rsvg.h> |
38 | |
39 | #include <nsutils/endian.h> |
40 | |
41 | #include "utils/log.h" |
42 | #include "utils/utils.h" |
43 | #include "utils/messages.h" |
44 | #include "netsurf/plotters.h" |
45 | #include "netsurf/bitmap.h" |
46 | #include "netsurf/content.h" |
47 | #include "content/llcache.h" |
48 | #include "content/content_protected.h" |
49 | #include "content/content_factory.h" |
50 | #include "desktop/gui_internal.h" |
51 | #include "desktop/bitmap.h" |
52 | |
53 | #include "image/image_cache.h" |
54 | |
55 | #include "image/rsvg.h" |
56 | |
57 | |
58 | typedef struct rsvg_content { |
59 | struct content base; |
60 | |
61 | RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */ |
62 | } rsvg_content; |
63 | |
64 | |
65 | static nserror |
66 | rsvg_create(const content_handler *handler, |
67 | lwc_string *imime_type, |
68 | const struct http_parameter *params, |
69 | llcache_handle *llcache, |
70 | const char *fallback_charset, |
71 | bool_Bool quirks, |
72 | struct content **c) |
73 | { |
74 | rsvg_content *svg; |
75 | nserror error; |
76 | |
77 | svg = calloc(1, sizeof(rsvg_content)); |
78 | if (svg == NULL((void*)0)) |
79 | return NSERROR_NOMEM; |
80 | |
81 | error = content__init(&svg->base, handler, imime_type, params, |
82 | llcache, fallback_charset, quirks); |
83 | if (error != NSERROR_OK) { |
84 | free(svg); |
85 | return error; |
86 | } |
87 | |
88 | *c = (struct content *)svg; |
89 | |
90 | return NSERROR_OK; |
91 | } |
92 | |
93 | |
94 | /** |
95 | * create a bitmap from jpeg content for the image cache. |
96 | */ |
97 | static struct bitmap * |
98 | rsvg_cache_convert(struct content *c) |
99 | { |
100 | rsvg_content *svgc = (rsvg_content *)c; |
101 | struct bitmap *bitmap; |
102 | cairo_surface_t *cs; |
103 | cairo_t *cr; |
104 | RsvgRectangle viewport; |
105 | gboolean renderres; |
106 | |
107 | if ((bitmap = guit->bitmap->create(c->width, c->height, BITMAP_NONE)) == NULL((void*)0)) { |
108 | NSLOG(netsurf, INFO, "Failed to create bitmap for rsvg render.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 108, }; nslog__log(&_nslog_ctx , "Failed to create bitmap for rsvg render."); } } while(0); |
109 | return NULL((void*)0); |
110 | } |
111 | |
112 | if ((cs = cairo_image_surface_create_for_data( |
113 | (unsigned char *)guit->bitmap->get_buffer(bitmap), |
114 | CAIRO_FORMAT_ARGB32, |
115 | c->width, c->height, |
116 | guit->bitmap->get_rowstride(bitmap))) == NULL((void*)0)) { |
117 | NSLOG(netsurf, INFO, "Failed to create Cairo image surface for rsvg render.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 117, }; nslog__log(&_nslog_ctx , "Failed to create Cairo image surface for rsvg render."); } } while(0); |
118 | guit->bitmap->destroy(bitmap); |
119 | return NULL((void*)0); |
120 | } |
121 | if ((cr = cairo_create(cs)) == NULL((void*)0)) { |
122 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 123, }; nslog__log(&_nslog_ctx , "Failed to create Cairo drawing context for rsvg render."); } } while(0) |
123 | "Failed to create Cairo drawing context for rsvg render.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 123, }; nslog__log(&_nslog_ctx , "Failed to create Cairo drawing context for rsvg render."); } } while(0); |
124 | cairo_surface_destroy(cs); |
125 | guit->bitmap->destroy(bitmap); |
126 | return NULL((void*)0); |
127 | } |
128 | |
129 | viewport.x = 0; |
130 | viewport.y = 0; |
131 | viewport.width = c->width; |
132 | viewport.height = c->height; |
133 | renderres = rsvg_handle_render_document(svgc->rsvgh, cr, &viewport, NULL((void*)0)); |
Value stored to 'renderres' is never read | |
134 | NSLOG(netsurf, DEBUG, "rsvg render:%d, width:%d, height %d", renderres, c->width, c->height)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_DEBUG, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 134, }; nslog__log(&_nslog_ctx , "rsvg render:%d, width:%d, height %d", renderres, c->width , c->height); } } while(0); |
135 | |
136 | bitmap_format_to_client(bitmap, &(bitmap_fmt_t) { |
137 | .layout = BITMAP_LAYOUT_ARGB8888, |
138 | }); |
139 | guit->bitmap->modified(bitmap); |
140 | |
141 | cairo_destroy(cr); |
142 | cairo_surface_destroy(cs); |
143 | |
144 | return bitmap; |
145 | } |
146 | |
147 | static void rsvg__get_demensions(const rsvg_content *svgc, |
148 | int *width, int *height) |
149 | { |
150 | #if LIBRSVG_MAJOR_VERSION(2) >= 2 && LIBRSVG_MINOR_VERSION(54) >= 52 |
151 | gdouble rwidth; |
152 | gdouble rheight; |
153 | gboolean gotsize; |
154 | |
155 | gotsize = rsvg_handle_get_intrinsic_size_in_pixels(svgc->rsvgh, |
156 | &rwidth, |
157 | &rheight); |
158 | if (gotsize == TRUE(!(0))) { |
159 | *width = rwidth; |
160 | *height = rheight; |
161 | } else { |
162 | RsvgRectangle ink_rect; |
163 | RsvgRectangle logical_rect; |
164 | rsvg_handle_get_geometry_for_element(svgc->rsvgh, |
165 | NULL((void*)0), |
166 | &ink_rect, |
167 | &logical_rect, |
168 | NULL((void*)0)); |
169 | *width = ink_rect.width; |
170 | *height = ink_rect.height; |
171 | } |
172 | #else |
173 | RsvgDimensionData rsvgsize; |
174 | |
175 | rsvg_handle_get_dimensions(svgc->rsvgh, &rsvgsize); |
176 | *width = rsvgsize.width; |
177 | *height = rsvgsize.height; |
178 | #endif |
179 | NSLOG(netsurf, DEBUG, "rsvg width:%d height:%d.", *width, *height)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_DEBUG, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 179, }; nslog__log(&_nslog_ctx , "rsvg width:%d height:%d.", *width, *height); } } while(0); |
180 | } |
181 | |
182 | static bool_Bool rsvg_convert(struct content *c) |
183 | { |
184 | rsvg_content *svgc = (rsvg_content *)c; |
185 | const uint8_t *data; /* content data */ |
186 | size_t size; /* content data size */ |
187 | GInputStream * istream; |
188 | GError *gerror = NULL((void*)0); |
189 | |
190 | /* check image header is valid and get width/height */ |
191 | |
192 | data = content__get_source_data(c, &size); |
193 | |
194 | istream = g_memory_input_stream_new_from_data(data, size, NULL((void*)0)); |
195 | svgc->rsvgh = rsvg_handle_new_from_stream_sync(istream, |
196 | NULL((void*)0), |
197 | RSVG_HANDLE_FLAGS_NONE, |
198 | NULL((void*)0), |
199 | &gerror); |
200 | g_object_unref(istream); |
201 | if (svgc->rsvgh == NULL((void*)0)) { |
202 | NSLOG(netsurf, INFO, "Failed to create rsvg handle for content.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/image/rsvg246.c", sizeof ("content/handlers/image/rsvg246.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 202, }; nslog__log(&_nslog_ctx , "Failed to create rsvg handle for content."); } } while(0); |
203 | return false0; |
204 | } |
205 | |
206 | rsvg__get_demensions(svgc, &c->width, &c->height); |
207 | |
208 | c->size = c->width * c->height * 4; |
209 | |
210 | image_cache_add(c, NULL((void*)0), rsvg_cache_convert); |
211 | |
212 | content_set_ready(c); |
213 | content_set_done(c); |
214 | content_set_status(c, ""); /* Done: update status bar */ |
215 | |
216 | return true1; |
217 | } |
218 | |
219 | |
220 | static nserror rsvg_clone(const struct content *old, struct content **newc) |
221 | { |
222 | rsvg_content *svg; |
223 | nserror error; |
224 | |
225 | svg = calloc(1, sizeof(rsvg_content)); |
226 | if (svg == NULL((void*)0)) |
227 | return NSERROR_NOMEM; |
228 | |
229 | error = content__clone(old, &svg->base); |
230 | if (error != NSERROR_OK) { |
231 | content_destroy(&svg->base); |
232 | return error; |
233 | } |
234 | |
235 | /* re-convert if the content is ready */ |
236 | if ((old->status == CONTENT_STATUS_READY) || |
237 | (old->status == CONTENT_STATUS_DONE)) { |
238 | if (rsvg_convert(&svg->base) == false0) { |
239 | content_destroy(&svg->base); |
240 | return NSERROR_CLONE_FAILED; |
241 | } |
242 | } |
243 | |
244 | *newc = (struct content *)svg; |
245 | |
246 | return NSERROR_OK; |
247 | } |
248 | |
249 | |
250 | static void rsvg_destroy(struct content *c) |
251 | { |
252 | rsvg_content *d = (rsvg_content *) c; |
253 | |
254 | if (d->rsvgh != NULL((void*)0)) { |
255 | g_object_unref(d->rsvgh); |
256 | d->rsvgh = NULL((void*)0); |
257 | } |
258 | |
259 | return image_cache_destroy(c); |
260 | } |
261 | |
262 | static const content_handler rsvg_content_handler = { |
263 | .create = rsvg_create, |
264 | .data_complete = rsvg_convert, |
265 | .destroy = rsvg_destroy, |
266 | .redraw = image_cache_redraw, |
267 | .clone = rsvg_clone, |
268 | .get_internal = image_cache_get_internal, |
269 | .type = image_cache_content_type, |
270 | .is_opaque = image_cache_is_opaque, |
271 | .no_share = false0, |
272 | }; |
273 | |
274 | static const char *rsvg_types[] = { |
275 | "image/svg", |
276 | "image/svg+xml" |
277 | }; |
278 | |
279 | CONTENT_FACTORY_REGISTER_TYPES(nsrsvg, rsvg_types, rsvg_content_handler)nserror nsrsvg_init(void) { uint32_t i; nserror error = NSERROR_OK ; for (i = 0; i < (sizeof(rsvg_types)/sizeof(*(rsvg_types) )); i++) { error = content_factory_register_handler( rsvg_types [i], &rsvg_content_handler); if (error != NSERROR_OK) break ; } return error; }; |
280 |