NetSurf
rsvg246.c
Go to the documentation of this file.
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"
51#include "desktop/bitmap.h"
52
53#include "image/image_cache.h"
54
55#include "image/rsvg.h"
56
57
58typedef struct rsvg_content {
59 struct content base;
60
61 RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */
63
64
65static nserror
67 lwc_string *imime_type,
68 const struct http_parameter *params,
70 const char *fallback_charset,
71 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)
79 return NSERROR_NOMEM;
80
81 error = content__init(&svg->base, handler, imime_type, params,
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 */
97static struct bitmap *
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) {
108 NSLOG(netsurf, INFO, "Failed to create bitmap for rsvg render.");
109 return NULL;
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) {
117 NSLOG(netsurf, INFO, "Failed to create Cairo image surface for rsvg render.");
119 return NULL;
120 }
121 if ((cr = cairo_create(cs)) == NULL) {
122 NSLOG(netsurf, INFO,
123 "Failed to create Cairo drawing context for rsvg render.");
124 cairo_surface_destroy(cs);
126 return NULL;
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);
134 NSLOG(netsurf, DEBUG, "rsvg render:%d, width:%d, height %d", renderres, c->width, c->height);
135
137 .layout = BITMAP_LAYOUT_ARGB8888,
138 });
140
141 cairo_destroy(cr);
142 cairo_surface_destroy(cs);
143
144 return bitmap;
145}
146
147static void rsvg__get_demensions(const rsvg_content *svgc,
148 int *width, int *height)
149{
150#if LIBRSVG_MAJOR_VERSION >= 2 && LIBRSVG_MINOR_VERSION >= 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) {
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,
166 &ink_rect,
167 &logical_rect,
168 NULL);
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);
180}
181
182static 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;
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);
195 svgc->rsvgh = rsvg_handle_new_from_stream_sync(istream,
196 NULL,
197 RSVG_HANDLE_FLAGS_NONE,
198 NULL,
199 &gerror);
200 g_object_unref(istream);
201 if (svgc->rsvgh == NULL) {
202 NSLOG(netsurf, INFO, "Failed to create rsvg handle for content.");
203 return false;
204 }
205
206 rsvg__get_demensions(svgc, &c->width, &c->height);
207
208 c->size = c->width * c->height * 4;
209
211
214 content_set_status(c, ""); /* Done: update status bar */
215
216 return true;
217}
218
219
220static 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)
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) == false) {
239 content_destroy(&svg->base);
241 }
242 }
243
244 *newc = (struct content *)svg;
245
246 return NSERROR_OK;
247}
248
249
250static void rsvg_destroy(struct content *c)
251{
252 rsvg_content *d = (rsvg_content *) c;
253
254 if (d->rsvgh != NULL) {
255 g_object_unref(d->rsvgh);
256 d->rsvgh = NULL;
257 }
258
259 return image_cache_destroy(c);
260}
261
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,
270 .is_opaque = image_cache_is_opaque,
271 .no_share = false,
272};
273
274static const char *rsvg_types[] = {
275 "image/svg",
276 "image/svg+xml"
277};
278
280
void content_destroy(struct content *c)
Destroy and free a content.
Definition: content.c:354
void content_set_done(struct content *c)
Put a content in status CONTENT_STATUS_DONE.
Definition: content.c:299
nserror content__init(struct content *c, const content_handler *handler, lwc_string *imime_type, const struct http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks)
Definition: content.c:190
const uint8_t * content__get_source_data(struct content *c, size_t *size)
Retrieve source of content.
Definition: content.c:1216
nserror content__clone(const struct content *c, struct content *nc)
Clone a content's data members.
Definition: content.c:1382
void content_set_ready(struct content *c)
Put a content in status CONTENT_STATUS_READY and unlock the content.
Definition: content.c:285
void content_set_status(struct content *c, const char *status_message)
Updates content with new status.
Definition: content.c:270
Protected interface to Content handling.
@ CONTENT_STATUS_READY
Some parts of content still being loaded, but can be displayed.
Definition: content_type.h:92
@ CONTENT_STATUS_DONE
Content has completed all processing.
Definition: content_type.h:95
Internal core bitmap interface.
static void bitmap_format_to_client(void *bitmap, const bitmap_fmt_t *current_fmt)
Convert a bitmap to the client bitmap format.
Definition: bitmap.h:117
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_CLONE_FAILED
Failed to clone handle.
Definition: errors.h:37
@ NSERROR_OK
No error.
Definition: errors.h:30
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:50
Interface to core interface table.
content_type image_cache_content_type(void)
Definition: image_cache.c:873
void * image_cache_get_internal(const struct content *c, void *context)
Definition: image_cache.c:856
bool image_cache_redraw(struct content *c, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Generic content redraw callback.
Definition: image_cache.c:798
void image_cache_destroy(struct content *content)
Definition: image_cache.c:841
nserror image_cache_add(struct content *content, struct bitmap *bitmap, image_cache_convert_fn *convert)
adds an image content to be cached.
Definition: image_cache.c:510
bool image_cache_is_opaque(struct content *c)
Definition: image_cache.c:862
The image content handler intermediate image cache.
Generic bitmap handling interface.
@ BITMAP_NONE
Definition: bitmap.h:37
@ BITMAP_LAYOUT_ARGB8888
32-bit ARGB (0xAARRGGBB).
Definition: bitmap.h:83
Public content interface.
Target independent plotting interface.
static struct llcache_s * llcache
low level cache state
Definition: llcache.c:267
Low-level resource cache (interface)
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
Localised message support (interface).
int width
Definition: gui.c:160
int height
Definition: gui.c:161
CONTENT_FACTORY_REGISTER_TYPES(nsrsvg, rsvg_types, rsvg_content_handler)
static nserror rsvg_create(const content_handler *handler, lwc_string *imime_type, const struct http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c)
Definition: rsvg246.c:66
static struct bitmap * rsvg_cache_convert(struct content *c)
create a bitmap from jpeg content for the image cache.
Definition: rsvg246.c:98
static bool rsvg_convert(struct content *c)
Definition: rsvg246.c:182
static const char * rsvg_types[]
Definition: rsvg246.c:274
struct rsvg_content rsvg_content
static void rsvg__get_demensions(const rsvg_content *svgc, int *width, int *height)
Definition: rsvg246.c:147
static const content_handler rsvg_content_handler
Definition: rsvg246.c:262
static void rsvg_destroy(struct content *c)
Definition: rsvg246.c:250
static nserror rsvg_clone(const struct content *old, struct content **newc)
Definition: rsvg246.c:220
Content handler for image/svg using librsvg (interface).
Interface to utility string handling.
Bitmap format specifier.
Definition: bitmap.h:95
RISC OS wimp toolkit bitmap.
Definition: bitmap.c:68
uint32 size
Definition: bitmap.c:73
Content operation function table.
nserror(* create)(const struct content_handler *handler, lwc_string *imime_type, const struct http_parameter *params, struct llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c)
Content which corresponds to a single URL.
bool quirks
Content is in quirks mode.
int height
Height dimension, if applicable.
char * fallback_charset
Fallback charset, or NULL.
int width
Width dimension, if applicable.
const struct content_handler * handler
Handler for content.
content_status status
Current status.
unsigned int size
Estimated size of all data associated with this content.
void(* destroy)(void *bitmap)
Destroy a bitmap.
Definition: bitmap.h:143
void *(* create)(int width, int height, enum gui_bitmap_flags flags)
Create a new bitmap.
Definition: bitmap.h:136
size_t(* get_rowstride)(void *bitmap)
Get the number of bytes per row of the image.
Definition: bitmap.h:177
void(* modified)(void *bitmap)
Marks a bitmap as modified.
Definition: bitmap.h:200
unsigned char *(* get_buffer)(void *bitmap)
Get the image buffer from a bitmap.
Definition: bitmap.h:169
Representation of an HTTP parameter.
Definition: parameter.c:31
Handle to low-level cache object.
Definition: llcache.c:76
struct gui_bitmap_table * bitmap
Bitmap table.
Definition: gui_table.h:153
struct content base
Definition: rsvg.c:59
RsvgHandle * rsvgh
Context handle for RSVG renderer.
Definition: rsvg.c:61
Interface to a number of general purpose functionality.
static nserror bitmap(const struct redraw_context *ctx, struct bitmap *bitmap, int x, int y, int width, int height, colour bg, bitmap_flags_t flags)
Plot a bitmap.
Definition: plot.c:857