NetSurf
svg.c
Go to the documentation of this file.
1/*
2 * Copyright 2007-2008 James Bursa <bursa@users.sourceforge.net>
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 for image/svg using libsvgtiny.
22 */
23
24#include <assert.h>
25#include <limits.h>
26#include <string.h>
27#include <stdlib.h>
28
29#include <svgtiny.h>
30
31#include "utils/messages.h"
32#include "utils/utils.h"
33#include "utils/nsurl.h"
34#include "netsurf/plotters.h"
35#include "netsurf/content.h"
38
39#include "image/svg.h"
40
41typedef struct svg_content {
42 struct content base;
43
44 struct svgtiny_diagram *diagram;
45
49
50
51
53{
54 c->diagram = svgtiny_create();
55 if (c->diagram == NULL)
56 goto no_memory;
57
58 c->current_width = INT_MAX;
59 c->current_height = INT_MAX;
60
61 return NSERROR_OK;
62
63no_memory:
65 return NSERROR_NOMEM;
66}
67
68
69/**
70 * Create a CONTENT_SVG.
71 */
72
73static nserror svg_create(const content_handler *handler,
74 lwc_string *imime_type, const struct http_parameter *params,
75 struct llcache_handle *llcache, const char *fallback_charset,
76 bool quirks, struct content **c)
77{
78 svg_content *svg;
79 nserror error;
80
81 svg = calloc(1, sizeof(svg_content));
82 if (svg == NULL)
83 return NSERROR_NOMEM;
84
85 error = content__init(&svg->base, handler, imime_type, params,
86 llcache, fallback_charset, quirks);
87 if (error != NSERROR_OK) {
88 free(svg);
89 return error;
90 }
91
92 error = svg_create_svg_data(svg);
93 if (error != NSERROR_OK) {
94 free(svg);
95 return error;
96 }
97
98 *c = (struct content *) svg;
99
100 return NSERROR_OK;
101}
102
103
104
105/**
106 * Convert a CONTENT_SVG for display.
107 */
108
109static bool svg_convert(struct content *c)
110{
111 /*c->title = malloc(100);
112 if (c->title)
113 snprintf(c->title, 100, messages_get("svgTitle"),
114 width, height, c->source_size);*/
115 //c->size += ?;
118 /* Done: update status bar */
119 content_set_status(c, "");
120
121 return true;
122}
123
124/**
125 * Reformat a CONTENT_SVG.
126 */
127
128static void svg_reformat(struct content *c, int width, int height)
129{
130 svg_content *svg = (svg_content *) c;
131 const uint8_t *source_data;
132 size_t source_size;
133
134 assert(svg->diagram);
135
136 /* Avoid reformats to same width/height as we already reformatted to */
137 if (width != svg->current_width || height != svg->current_height) {
138 source_data = content__get_source_data(c, &source_size);
139
140 svgtiny_parse(svg->diagram,
141 (const char *)source_data,
142 source_size,
144 width,
145 height);
146
147 svg->current_width = width;
148 svg->current_height = height;
149 }
150
151 c->width = svg->diagram->width;
152 c->height = svg->diagram->height;
153}
154
155
156/**
157 * Redraw a CONTENT_SVG.
158 */
159
160static bool
162 int x,
163 int y,
164 int width,
165 int height,
166 const struct rect *clip,
167 const struct redraw_context *ctx,
168 float scale,
169 colour background_colour)
170{
171 float transform[6];
172 struct svgtiny_diagram *diagram = svg->diagram;
173 int px, py;
174 unsigned int i;
176 plot_style_t pstyle;
177 nserror res;
178
179 assert(diagram);
180
181 transform[0] = (float) width / (float) svg->base.width;
182 transform[1] = 0;
183 transform[2] = 0;
184 transform[3] = (float) height / (float) svg->base.height;
185 transform[4] = x;
186 transform[5] = y;
187
188#define BGR(c) (((svgtiny_RED((c))) | \
189 (svgtiny_GREEN((c)) << 8) | \
190 (svgtiny_BLUE((c)) << 16)))
191
192 for (i = 0; i != diagram->shape_count; i++) {
193 if (diagram->shape[i].path) {
194 /* stroke style */
195 if (diagram->shape[i].stroke == svgtiny_TRANSPARENT) {
198 } else {
200 pstyle.stroke_colour = BGR(diagram->shape[i].stroke);
201 }
203 diagram->shape[i].stroke_width);
204
205 /* fill style */
206 if (diagram->shape[i].fill == svgtiny_TRANSPARENT) {
209 } else {
211 pstyle.fill_colour = BGR(diagram->shape[i].fill);
212 }
213
214 /* draw the path */
215 res = ctx->plot->path(ctx,
216 &pstyle,
217 diagram->shape[i].path,
218 diagram->shape[i].path_length,
219 transform);
220 if (res != NSERROR_OK) {
221 return false;
222 }
223
224 } else if (diagram->shape[i].text) {
225 px = transform[0] * diagram->shape[i].text_x +
226 transform[2] * diagram->shape[i].text_y +
227 transform[4];
228 py = transform[1] * diagram->shape[i].text_x +
229 transform[3] * diagram->shape[i].text_y +
230 transform[5];
231
232 fstyle.background = 0xffffff;
233 fstyle.foreground = 0x000000;
234 fstyle.size = (8 * PLOT_STYLE_SCALE) * scale;
235
236 res = ctx->plot->text(ctx,
237 &fstyle,
238 px, py,
239 diagram->shape[i].text,
240 strlen(diagram->shape[i].text));
241 if (res != NSERROR_OK) {
242 return false;
243 }
244 }
245 }
246
247#undef BGR
248
249 return true;
250}
251
252
253static bool
255 struct content_redraw_data *data,
256 const struct rect *clip,
257 const struct redraw_context *ctx)
258{
259 /* Tiled redraw required. SVG repeats to extents of clip
260 * rectangle, in x, y or both directions */
261 int x, y, x0, y0, x1, y1;
262
263 x = x0 = data->x;
264 y = y0 = data->y;
265
266 /* Find the redraw boundaries to loop within */
267 if (data->repeat_x) {
268 for (; x0 > clip->x0; x0 -= data->width);
269 x1 = clip->x1;
270 } else {
271 x1 = x + 1;
272 }
273 if (data->repeat_y) {
274 for (; y0 > clip->y0; y0 -= data->height);
275 y1 = clip->y1;
276 } else {
277 y1 = y + 1;
278 }
279
280 /* Repeatedly plot the SVG across the area */
281 for (y = y0; y < y1; y += data->height) {
282 for (x = x0; x < x1; x += data->width) {
283 if (!svg_redraw_internal(svg, x, y,
284 data->width, data->height,
285 clip, ctx, data->scale,
286 data->background_colour)) {
287 return false;
288 }
289 }
290 }
291
292 return true;
293}
294
295
296/**
297 * Redraw a CONTENT_SVG.
298 */
299static bool
301 struct content_redraw_data *data,
302 const struct rect *clip,
303 const struct redraw_context *ctx)
304{
305 svg_content *svg = (svg_content *)c;
306
307 if ((data->width <= 0) && (data->height <= 0)) {
308 /* No point trying to plot SVG if it does not occupy a valid
309 * area */
310 return true;
311 }
312
313 if ((data->repeat_x == false) && (data->repeat_y == false)) {
314 /* Simple case: SVG is not tiled */
315 return svg_redraw_internal(svg, data->x, data->y,
316 data->width, data->height,
317 clip, ctx, data->scale,
318 data->background_colour);
319 }
320
321 return svg_redraw_tiled_internal(svg, data, clip, ctx);
322}
323
324
325/**
326 * Destroy a CONTENT_SVG and free all resources it owns.
327 */
328
329static void svg_destroy(struct content *c)
330{
331 svg_content *svg = (svg_content *) c;
332
333 if (svg->diagram != NULL)
334 svgtiny_free(svg->diagram);
335}
336
337
338static nserror svg_clone(const struct content *old, struct content **newc)
339{
340 svg_content *svg;
341 nserror error;
342
343 svg = calloc(1, sizeof(svg_content));
344 if (svg == NULL)
345 return NSERROR_NOMEM;
346
347 error = content__clone(old, &svg->base);
348 if (error != NSERROR_OK) {
349 content_destroy(&svg->base);
350 return error;
351 }
352
353 /* Simply replay create/convert */
354 error = svg_create_svg_data(svg);
355 if (error != NSERROR_OK) {
356 content_destroy(&svg->base);
357 return error;
358 }
359
360 if (old->status == CONTENT_STATUS_READY ||
361 old->status == CONTENT_STATUS_DONE) {
362 if (svg_convert(&svg->base) == false) {
363 content_destroy(&svg->base);
365 }
366 }
367
368 *newc = (struct content *) svg;
369
370 return NSERROR_OK;
371}
372
374{
375 return CONTENT_IMAGE;
376}
377
380 .data_complete = svg_convert,
381 .reformat = svg_reformat,
382 .destroy = svg_destroy,
383 .redraw = svg_redraw,
384 .clone = svg_clone,
385 .type = svg_content_type,
386 .no_share = true
387};
388
389static const char *svg_types[] = {
390 "image/svg",
391 "image/svg+xml"
392};
393
394
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
nsurl * content_get_url(struct content *c)
Retrieve URL associated with content.
Definition: content.c:1051
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
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
Public content interface.
Target independent plotting interface.
static struct llcache_s * llcache
low level cache state
Definition: llcache.c:267
Localised message support (interface).
NetSurf URL handling (interface).
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
plot_font_style_t const *const plot_style_font
Definition: plot_style.c:165
#define plot_style_int_to_fixed(v)
Definition: plot_style.h:51
@ PLOT_OP_TYPE_NONE
No operation.
Definition: plot_style.h:66
@ PLOT_OP_TYPE_SOLID
Solid colour.
Definition: plot_style.h:67
#define NS_TRANSPARENT
Transparent colour value.
Definition: plot_style.h:39
#define PLOT_STYLE_SCALE
Scaling factor for plot styles.
Definition: plot_style.h:45
int width
Definition: gui.c:160
int height
Definition: gui.c:161
Interface to utility string handling.
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
float scale
Scale for redraw (for scaling contents without intrinsic dimensions)
Definition: content.h:56
Content which corresponds to a single URL.
int height
Height dimension, if applicable.
int width
Width dimension, if applicable.
content_status status
Current status.
Representation of an HTTP parameter.
Definition: parameter.c:31
Handle to low-level cache object.
Definition: llcache.c:76
Font style for plotting.
Definition: plot_style.h:111
colour foreground
Colour of text.
Definition: plot_style.h:123
plot_style_fixed size
Font size, in pt.
Definition: plot_style.h:119
colour background
Background colour to blend to, if appropriate.
Definition: plot_style.h:122
Plot style for stroke/fill plotters.
Definition: plot_style.h:76
colour fill_colour
Colour of fill.
Definition: plot_style.h:81
plot_style_fixed stroke_width
Width of stroke, in pixels.
Definition: plot_style.h:78
plot_operation_type_t fill_type
Fill plot type.
Definition: plot_style.h:80
colour stroke_colour
Colour of stroke.
Definition: plot_style.h:79
plot_operation_type_t stroke_type
Stroke plot type.
Definition: plot_style.h:77
nserror(* text)(const struct redraw_context *ctx, const plot_font_style_t *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plotters.h:278
nserror(* path)(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plotters.h:226
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
struct svgtiny_diagram * diagram
Definition: svg.c:44
struct content base
Definition: svg.c:42
int current_height
Definition: svg.c:47
int current_width
Definition: svg.c:46
static void svg_destroy(struct content *c)
Destroy a CONTENT_SVG and free all resources it owns.
Definition: svg.c:329
struct svg_content svg_content
static const char * svg_types[]
Definition: svg.c:389
static bool svg_convert(struct content *c)
Convert a CONTENT_SVG for display.
Definition: svg.c:109
CONTENT_FACTORY_REGISTER_TYPES(svg, svg_types, svg_content_handler)
#define BGR(c)
static bool svg_redraw(struct content *c, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Redraw a CONTENT_SVG.
Definition: svg.c:300
static void svg_reformat(struct content *c, int width, int height)
Reformat a CONTENT_SVG.
Definition: svg.c:128
static nserror svg_create_svg_data(svg_content *c)
Definition: svg.c:52
static bool svg_redraw_internal(svg_content *svg, int x, int y, int width, int height, const struct rect *clip, const struct redraw_context *ctx, float scale, colour background_colour)
Redraw a CONTENT_SVG.
Definition: svg.c:161
static nserror svg_clone(const struct content *old, struct content **newc)
Definition: svg.c:338
static bool svg_redraw_tiled_internal(svg_content *svg, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Definition: svg.c:254
static const content_handler svg_content_handler
Definition: svg.c:378
static nserror svg_create(const 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)
Create a CONTENT_SVG.
Definition: svg.c:73
static content_type svg_content_type(void)
Definition: svg.c:373
Content for image/svg (interface).
uint32_t colour
Colour type: XBGR.
Definition: types.h:35
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