NetSurf
rsvg.c
Go to the documentation of this file.
1/*
2 * Copyright 2007 Rob Kendrick <rjek@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.
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#ifndef RSVG_CAIRO_H
39#include <librsvg/rsvg-cairo.h>
40#endif
41
42#include <nsutils/endian.h>
43
44#include "utils/log.h"
45#include "utils/utils.h"
46#include "utils/messages.h"
47#include "netsurf/plotters.h"
48#include "netsurf/bitmap.h"
49#include "netsurf/content.h"
50#include "content/llcache.h"
54#include "desktop/bitmap.h"
55
56#include "image/rsvg.h"
57
58typedef struct rsvg_content {
59 struct content base;
60
61 RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */
62 cairo_surface_t *cs; /**< The surface built inside a nsbitmap */
63 cairo_t *ct; /**< Cairo drawing context */
64 struct bitmap *bitmap; /**< Created NetSurf bitmap */
66
68{
69 c->rsvgh = NULL;
70 c->cs = NULL;
71 c->ct = NULL;
72 c->bitmap = NULL;
73
74 if ((c->rsvgh = rsvg_handle_new()) == NULL) {
75 NSLOG(netsurf, INFO, "rsvg_handle_new() returned NULL.");
77 return NSERROR_NOMEM;
78 }
79
80 return NSERROR_OK;
81}
82
83
84static nserror rsvg_create(const content_handler *handler,
85 lwc_string *imime_type, const struct http_parameter *params,
86 llcache_handle *llcache, const char *fallback_charset,
87 bool quirks, struct content **c)
88{
89 rsvg_content *svg;
90 nserror error;
91
92 svg = calloc(1, sizeof(rsvg_content));
93 if (svg == NULL)
94 return NSERROR_NOMEM;
95
96 error = content__init(&svg->base, handler, imime_type, params,
97 llcache, fallback_charset, quirks);
98 if (error != NSERROR_OK) {
99 free(svg);
100 return error;
101 }
102
103 error = rsvg_create_svg_data(svg);
104 if (error != NSERROR_OK) {
105 free(svg);
106 return error;
107 }
108
109 *c = (struct content *) svg;
110
111 return NSERROR_OK;
112}
113
114
115static bool rsvg_process_data(struct content *c, const char *data,
116 unsigned int size)
117{
118 rsvg_content *d = (rsvg_content *) c;
119 GError *err = NULL;
120
121 if (rsvg_handle_write(d->rsvgh, (const guchar *)data, (gsize)size,
122 &err) == FALSE) {
123 NSLOG(netsurf, INFO,
124 "rsvg_handle_write returned an error: %s", err->message);
126 return false;
127 }
128
129 return true;
130}
131
132static bool rsvg_convert(struct content *c)
133{
134 rsvg_content *d = (rsvg_content *) c;
135 RsvgDimensionData rsvgsize;
136 GError *err = NULL;
137
138 if (rsvg_handle_close(d->rsvgh, &err) == FALSE) {
139 NSLOG(netsurf, INFO,
140 "rsvg_handle_close returned an error: %s", err->message);
142 return false;
143 }
144
145 assert(err == NULL);
146
147 /* we should now be able to query librsvg for the natural size of the
148 * graphic, so we can create our bitmap.
149 */
150
151 rsvg_handle_get_dimensions(d->rsvgh, &rsvgsize);
152 c->width = rsvgsize.width;
153 c->height = rsvgsize.height;
154
155 if ((d->bitmap = guit->bitmap->create(c->width, c->height,
156 BITMAP_NONE)) == NULL) {
157 NSLOG(netsurf, INFO,
158 "Failed to create bitmap for rsvg render.");
160 return false;
161 }
162
163 if ((d->cs = cairo_image_surface_create_for_data(
164 (unsigned char *)guit->bitmap->get_buffer(d->bitmap),
165 CAIRO_FORMAT_ARGB32,
166 c->width, c->height,
167 guit->bitmap->get_rowstride(d->bitmap))) == NULL) {
168 NSLOG(netsurf, INFO,
169 "Failed to create Cairo image surface for rsvg render.");
171 return false;
172 }
173
174 if ((d->ct = cairo_create(d->cs)) == NULL) {
175 NSLOG(netsurf, INFO,
176 "Failed to create Cairo drawing context for rsvg render.");
178 return false;
179 }
180
181 rsvg_handle_render_cairo(d->rsvgh, d->ct);
182
184 .layout = BITMAP_LAYOUT_ARGB8888,
185 });
189 /* Done: update status bar */
190 content_set_status(c, "");
191
192 return true;
193}
194
195static bool rsvg_redraw(struct content *c, struct content_redraw_data *data,
196 const struct rect *clip, const struct redraw_context *ctx)
197{
198 rsvg_content *rsvgcontent = (rsvg_content *) c;
200
201 assert(rsvgcontent->bitmap != NULL);
202
203 if (data->repeat_x)
204 flags |= BITMAPF_REPEAT_X;
205 if (data->repeat_y)
206 flags |= BITMAPF_REPEAT_Y;
207
208 return (ctx->plot->bitmap(ctx,
209 rsvgcontent->bitmap,
210 data->x, data->y,
211 data->width, data->height,
212 data->background_colour,
213 flags) == NSERROR_OK);
214}
215
216static void rsvg_destroy(struct content *c)
217{
218 rsvg_content *d = (rsvg_content *) c;
219
220 if (d->bitmap != NULL) guit->bitmap->destroy(d->bitmap);
221 if (d->rsvgh != NULL) g_object_unref(d->rsvgh);
222 if (d->ct != NULL) cairo_destroy(d->ct);
223 if (d->cs != NULL) cairo_surface_destroy(d->cs);
224
225 return;
226}
227
228static nserror rsvg_clone(const struct content *old, struct content **newc)
229{
230 rsvg_content *svg;
231 nserror error;
232 const uint8_t *data;
233 size_t size;
234
235 svg = calloc(1, sizeof(rsvg_content));
236 if (svg == NULL)
237 return NSERROR_NOMEM;
238
239 error = content__clone(old, &svg->base);
240 if (error != NSERROR_OK) {
241 content_destroy(&svg->base);
242 return error;
243 }
244
245 /* Simply replay create/process/convert */
246 error = rsvg_create_svg_data(svg);
247 if (error != NSERROR_OK) {
248 content_destroy(&svg->base);
249 return error;
250 }
251
252 data = content__get_source_data(&svg->base, &size);
253 if (size > 0) {
254 if (rsvg_process_data(&svg->base, (const char *)data, size) == false) {
255 content_destroy(&svg->base);
256 return NSERROR_NOMEM;
257 }
258 }
259
260 if (old->status == CONTENT_STATUS_READY ||
261 old->status == CONTENT_STATUS_DONE) {
262 if (rsvg_convert(&svg->base) == false) {
263 content_destroy(&svg->base);
265 }
266 }
267
268 *newc = (struct content *) svg;
269
270 return NSERROR_OK;
271}
272
273static void *rsvg_get_internal(const struct content *c, void *context)
274{
275 rsvg_content *d = (rsvg_content *) c;
276
277 return d->bitmap;
278}
279
281{
282 return CONTENT_IMAGE;
283}
284
285
286static bool rsvg_content_is_opaque(struct content *c)
287{
288 rsvg_content *d = (rsvg_content *) c;
289
290 if (d->bitmap != NULL) {
291 return guit->bitmap->get_opaque(d->bitmap);
292 }
293
294 return false;
295}
296
297
300 .process_data = rsvg_process_data,
301 .data_complete = rsvg_convert,
302 .destroy = rsvg_destroy,
303 .redraw = rsvg_redraw,
304 .clone = rsvg_clone,
305 .get_internal = rsvg_get_internal,
306 .type = rsvg_content_type,
307 .is_opaque = rsvg_content_is_opaque,
308 .no_share = false,
309};
310
311static const char *rsvg_types[] = {
312 "image/svg",
313 "image/svg+xml"
314};
315
317
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
void content_broadcast_error(struct content *c, nserror errorcode, const char *msg)
Send an error message to all users.
Definition: content.c:769
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
content_type
The type of a content.
Definition: content_type.h:53
@ CONTENT_IMAGE
All images.
Definition: content_type.h:67
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_SVG_ERROR
A SVG error occurred.
Definition: errors.h:44
@ 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:49
Interface to core interface table.
Generic bitmap handling interface.
@ BITMAP_NONE
Definition: bitmap.h:37
Public content interface.
Target independent plotting interface.
#define BITMAPF_REPEAT_X
Definition: plotters.h:38
#define BITMAPF_REPEAT_Y
Definition: plotters.h:39
unsigned long bitmap_flags_t
Definition: plotters.h:36
#define BITMAPF_NONE
Definition: plotters.h:37
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).
static bool rsvg_redraw(struct content *c, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Definition: rsvg.c:195
CONTENT_FACTORY_REGISTER_TYPES(nsrsvg, rsvg_types, rsvg_content_handler)
static bool rsvg_content_is_opaque(struct content *c)
Definition: rsvg.c:286
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: rsvg.c:84
static nserror rsvg_create_svg_data(rsvg_content *c)
Definition: rsvg.c:67
static void * rsvg_get_internal(const struct content *c, void *context)
Definition: rsvg.c:273
static bool rsvg_convert(struct content *c)
Definition: rsvg.c:132
static const char * rsvg_types[]
Definition: rsvg.c:311
static bool rsvg_process_data(struct content *c, const char *data, unsigned int size)
Definition: rsvg.c:115
struct rsvg_content rsvg_content
static const content_handler rsvg_content_handler
Definition: rsvg.c:298
static void rsvg_destroy(struct content *c)
Definition: rsvg.c:216
static nserror rsvg_clone(const struct content *old, struct content **newc)
Definition: rsvg.c:228
static content_type rsvg_content_type(void)
Definition: rsvg.c:280
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
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)
parameters to content redraw
Definition: content.h:40
int height
vertical dimension
Definition: content.h:48
bool repeat_y
whether content is tiled in y direction
Definition: content.h:59
bool repeat_x
whether content is tiled in x direction
Definition: content.h:58
int y
coordinate for top-left of redraw
Definition: content.h:42
int x
coordinate for top-left of redraw
Definition: content.h:41
colour background_colour
The background colour.
Definition: content.h:51
int width
dimensions to render content at (for scaling contents with intrinsic dimensions)
Definition: content.h:47
Content which corresponds to a single URL.
int height
Height dimension, if applicable.
int width
Width dimension, if applicable.
struct textsearch_context * context
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
bool(* get_opaque)(void *bitmap)
Get the opacity of a bitmap.
Definition: bitmap.h:159
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:144
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: plotters.h:257
Rectangle coordinates.
Definition: types.h:40
Redraw context.
Definition: plotters.h:51
const struct plotter_table * plot
Current plot operation table.
Definition: plotters.h:73
cairo_surface_t * cs
The surface built inside a nsbitmap.
Definition: rsvg.c:62
struct content base
Definition: rsvg.c:59
RsvgHandle * rsvgh
Context handle for RSVG renderer.
Definition: rsvg.c:61
struct bitmap * bitmap
Created NetSurf bitmap.
Definition: rsvg.c:64
cairo_t * ct
Cairo drawing context.
Definition: rsvg.c:63
Interface to a number of general purpose functionality.
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357