mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-25 13:37:02 +03:00
Add support for transform, color none, and some colours in style attribute.
svn path=/trunk/netsurf/; revision=3654
This commit is contained in:
parent
f386520ff2
commit
069525fe89
122
image/svg.c
122
image/svg.c
@ -20,6 +20,7 @@
|
|||||||
* Content for image/svg (implementation).
|
* Content for image/svg (implementation).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE /* for strndup */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -77,6 +78,8 @@ static void svg_parse_paint_attributes(const xmlNode *node,
|
|||||||
static void svg_parse_color(const char *s, colour *c);
|
static void svg_parse_color(const char *s, colour *c);
|
||||||
static void svg_parse_font_attributes(const xmlNode *node,
|
static void svg_parse_font_attributes(const xmlNode *node,
|
||||||
struct svg_redraw_state *state);
|
struct svg_redraw_state *state);
|
||||||
|
static void svg_parse_transform_attributes(const xmlNode *node,
|
||||||
|
struct svg_redraw_state *state);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,6 +141,7 @@ bool svg_convert(struct content *c, int w, int h)
|
|||||||
struct svg_redraw_state state;
|
struct svg_redraw_state state;
|
||||||
state.viewport_width = w;
|
state.viewport_width = w;
|
||||||
state.viewport_height = h;
|
state.viewport_height = h;
|
||||||
|
state.style = css_base_style;
|
||||||
float x, y, width, height;
|
float x, y, width, height;
|
||||||
svg_parse_position_attributes(svg, state, &x, &y, &width, &height);
|
svg_parse_position_attributes(svg, state, &x, &y, &width, &height);
|
||||||
c->width = width;
|
c->width = width;
|
||||||
@ -180,6 +184,8 @@ bool svg_redraw(struct content *c, int x, int y,
|
|||||||
state.style.font_size.value.length.value = option_font_size * 0.1;
|
state.style.font_size.value.length.value = option_font_size * 0.1;
|
||||||
state.fill = 0x000000;
|
state.fill = 0x000000;
|
||||||
state.stroke = TRANSPARENT;
|
state.stroke = TRANSPARENT;
|
||||||
|
state.fill = TRANSPARENT;
|
||||||
|
state.stroke = 0x000000;
|
||||||
state.stroke_width = 1;
|
state.stroke_width = 1;
|
||||||
|
|
||||||
plot.clg(0xffffff);
|
plot.clg(0xffffff);
|
||||||
@ -218,6 +224,8 @@ bool svg_redraw_svg(xmlNode *svg, struct svg_redraw_state state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svg_parse_transform_attributes(svg, &state);
|
||||||
|
|
||||||
for (xmlNode *child = svg->children; child; child = child->next) {
|
for (xmlNode *child = svg->children; child; child = child->next) {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
@ -253,6 +261,7 @@ bool svg_redraw_svg(xmlNode *svg, struct svg_redraw_state state)
|
|||||||
bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
||||||
{
|
{
|
||||||
svg_parse_paint_attributes(path, &state);
|
svg_parse_paint_attributes(path, &state);
|
||||||
|
svg_parse_transform_attributes(path, &state);
|
||||||
|
|
||||||
/* read d attribute */
|
/* read d attribute */
|
||||||
char *s = (char *) xmlGetProp(path, (const xmlChar *) "d");
|
char *s = (char *) xmlGetProp(path, (const xmlChar *) "d");
|
||||||
@ -280,11 +289,11 @@ bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
|||||||
float x, y, x1, y1, x2, y2;
|
float x, y, x1, y1, x2, y2;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
LOG(("s \"%s\"", s));
|
/*LOG(("s \"%s\"", s));*/
|
||||||
|
|
||||||
/* M, m, L, l (2 arguments) */
|
/* M, m, L, l (2 arguments) */
|
||||||
if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) {
|
if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) {
|
||||||
LOG(("moveto or lineto"));
|
/*LOG(("moveto or lineto"));*/
|
||||||
if (*command == 'M' || *command == 'm')
|
if (*command == 'M' || *command == 'm')
|
||||||
plot_command = PLOTTER_PATH_MOVE;
|
plot_command = PLOTTER_PATH_MOVE;
|
||||||
else
|
else
|
||||||
@ -303,13 +312,13 @@ bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
|||||||
|
|
||||||
/* Z, z (no arguments) */
|
/* Z, z (no arguments) */
|
||||||
} else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) {
|
} else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) {
|
||||||
LOG(("closepath"));
|
/*LOG(("closepath"));*/
|
||||||
p[i++] = PLOTTER_PATH_CLOSE;
|
p[i++] = PLOTTER_PATH_CLOSE;
|
||||||
s += n;
|
s += n;
|
||||||
|
|
||||||
/* H, h (1 argument) */
|
/* H, h (1 argument) */
|
||||||
} else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) {
|
} else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) {
|
||||||
LOG(("horizontal lineto"));
|
/*LOG(("horizontal lineto"));*/
|
||||||
do {
|
do {
|
||||||
p[i++] = PLOTTER_PATH_LINE;
|
p[i++] = PLOTTER_PATH_LINE;
|
||||||
if (*command == 'h')
|
if (*command == 'h')
|
||||||
@ -321,7 +330,7 @@ bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
|||||||
|
|
||||||
/* V, v (1 argument) */
|
/* V, v (1 argument) */
|
||||||
} else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) {
|
} else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) {
|
||||||
LOG(("vertical lineto"));
|
/*LOG(("vertical lineto"));*/
|
||||||
do {
|
do {
|
||||||
p[i++] = PLOTTER_PATH_LINE;
|
p[i++] = PLOTTER_PATH_LINE;
|
||||||
if (*command == 'v')
|
if (*command == 'v')
|
||||||
@ -334,7 +343,7 @@ bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
|||||||
/* C, c (6 arguments) */
|
/* C, c (6 arguments) */
|
||||||
} else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command,
|
} else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command,
|
||||||
&x1, &y1, &x2, &y2, &x, &y, &n) == 7) {
|
&x1, &y1, &x2, &y2, &x, &y, &n) == 7) {
|
||||||
LOG(("curveto"));
|
/*LOG(("curveto"));*/
|
||||||
do {
|
do {
|
||||||
p[i++] = PLOTTER_PATH_BEZIER;
|
p[i++] = PLOTTER_PATH_BEZIER;
|
||||||
if (*command == 'c') {
|
if (*command == 'c') {
|
||||||
@ -356,22 +365,22 @@ bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state)
|
|||||||
&x1, &y1, &x2, &y2, &x, &y, &n) == 7);
|
&x1, &y1, &x2, &y2, &x, &y, &n) == 7);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG(("parse failed"));
|
/*LOG(("parse failed"));*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(("path:"));
|
/*LOG(("path:"));
|
||||||
for (unsigned int j = 0; j != i; j++) {
|
for (unsigned int j = 0; j != i; j++) {
|
||||||
LOG((" %f", p[j]));
|
LOG((" %f", p[j]));
|
||||||
}
|
}*/
|
||||||
|
|
||||||
bool ok = plot.path(p, i, state.fill, state.stroke_width, state.stroke,
|
bool ok = plot.path(p, i, state.fill, state.stroke_width, state.stroke,
|
||||||
&state.ctm.a);
|
&state.ctm.a);
|
||||||
|
|
||||||
free(p);
|
free(p);
|
||||||
|
|
||||||
return true;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -386,6 +395,7 @@ bool svg_redraw_rect(xmlNode *rect, struct svg_redraw_state state)
|
|||||||
svg_parse_position_attributes(rect, state,
|
svg_parse_position_attributes(rect, state,
|
||||||
&x, &y, &width, &height);
|
&x, &y, &width, &height);
|
||||||
svg_parse_paint_attributes(rect, &state);
|
svg_parse_paint_attributes(rect, &state);
|
||||||
|
svg_parse_transform_attributes(rect, &state);
|
||||||
|
|
||||||
int p[8] = { x, y,
|
int p[8] = { x, y,
|
||||||
x + width, y,
|
x + width, y,
|
||||||
@ -435,6 +445,7 @@ bool svg_redraw_circle(xmlNode *circle, struct svg_redraw_state state)
|
|||||||
state.viewport_width, state);
|
state.viewport_width, state);
|
||||||
}
|
}
|
||||||
svg_parse_paint_attributes(circle, &state);
|
svg_parse_paint_attributes(circle, &state);
|
||||||
|
svg_parse_transform_attributes(circle, &state);
|
||||||
|
|
||||||
int px = state.origin_x + state.ctm.a * x +
|
int px = state.origin_x + state.ctm.a * x +
|
||||||
state.ctm.c * y + state.ctm.e;
|
state.ctm.c * y + state.ctm.e;
|
||||||
@ -477,6 +488,7 @@ bool svg_redraw_line(xmlNode *line, struct svg_redraw_state state)
|
|||||||
state.viewport_height, state);
|
state.viewport_height, state);
|
||||||
}
|
}
|
||||||
svg_parse_paint_attributes(line, &state);
|
svg_parse_paint_attributes(line, &state);
|
||||||
|
svg_parse_transform_attributes(line, &state);
|
||||||
|
|
||||||
int px1 = state.origin_x + state.ctm.a * x1 +
|
int px1 = state.origin_x + state.ctm.a * x1 +
|
||||||
state.ctm.c * y1 + state.ctm.e;
|
state.ctm.c * y1 + state.ctm.e;
|
||||||
@ -503,12 +515,14 @@ bool svg_redraw_text(xmlNode *text, struct svg_redraw_state state)
|
|||||||
svg_parse_position_attributes(text, state,
|
svg_parse_position_attributes(text, state,
|
||||||
&x, &y, &width, &height);
|
&x, &y, &width, &height);
|
||||||
svg_parse_font_attributes(text, &state);
|
svg_parse_font_attributes(text, &state);
|
||||||
|
svg_parse_transform_attributes(text, &state);
|
||||||
|
|
||||||
int px = state.origin_x + state.ctm.a * x +
|
int px = state.origin_x + state.ctm.a * x +
|
||||||
state.ctm.c * y + state.ctm.e;
|
state.ctm.c * y + state.ctm.e;
|
||||||
int py = state.origin_y + state.ctm.b * x +
|
int py = state.origin_y + state.ctm.b * x +
|
||||||
state.ctm.d * y + state.ctm.f;
|
state.ctm.d * y + state.ctm.f;
|
||||||
state.ctm.e = px - state.origin_x;
|
/* state.ctm.e = px - state.origin_x; */
|
||||||
state.ctm.f = py - state.origin_y;
|
/* state.ctm.f = py - state.origin_y; */
|
||||||
|
|
||||||
struct css_style style = state.style;
|
struct css_style style = state.style;
|
||||||
style.font_size.value.length.value *= state.ctm.a;
|
style.font_size.value.length.value *= state.ctm.a;
|
||||||
@ -620,6 +634,34 @@ void svg_parse_paint_attributes(const xmlNode *node,
|
|||||||
state->stroke_width = svg_parse_length(
|
state->stroke_width = svg_parse_length(
|
||||||
attr->children->content,
|
attr->children->content,
|
||||||
state->viewport_width, *state);
|
state->viewport_width, *state);
|
||||||
|
else if (strcmp(attr->name, "style") == 0) {
|
||||||
|
const char *style = attr->children->content;
|
||||||
|
const char *s;
|
||||||
|
char *value;
|
||||||
|
if ((s = strstr(style, "fill:"))) {
|
||||||
|
s += 5;
|
||||||
|
while (*s == ' ')
|
||||||
|
s++;
|
||||||
|
value = strndup(s, strcspn(s, "; "));
|
||||||
|
svg_parse_color(value, &state->fill);
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
if ((s = strstr(style, "stroke:"))) {
|
||||||
|
s += 7;
|
||||||
|
while (*s == ' ')
|
||||||
|
s++;
|
||||||
|
value = strndup(s, strcspn(s, "; "));
|
||||||
|
svg_parse_color(value, &state->stroke);
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
if ((s = strstr(style, "stroke-width:"))) {
|
||||||
|
s += 13;
|
||||||
|
while (*s == ' ')
|
||||||
|
s++;
|
||||||
|
state->stroke_width = svg_parse_length(s,
|
||||||
|
state->viewport_width, *state);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,8 +694,12 @@ void svg_parse_color(const char *s, colour *c)
|
|||||||
r = rf * 255 / 100;
|
r = rf * 255 / 100;
|
||||||
*c = (b << 16) | (g << 8) | r;
|
*c = (b << 16) | (g << 8) | r;
|
||||||
}
|
}
|
||||||
|
} else if (len == 4 && strcmp(s, "none") == 0) {
|
||||||
|
*c = TRANSPARENT;
|
||||||
} else {
|
} else {
|
||||||
*c = named_colour(s);
|
colour named = named_colour(s);
|
||||||
|
if (named != CSS_COLOR_NONE)
|
||||||
|
*c = named;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,6 +725,56 @@ void svg_parse_font_attributes(const xmlNode *node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse transform attributes, if present.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void svg_parse_transform_attributes(const xmlNode *node,
|
||||||
|
struct svg_redraw_state *state)
|
||||||
|
{
|
||||||
|
float a, b, c, d, e, f;
|
||||||
|
float ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* parse transform */
|
||||||
|
xmlAttr *transform = xmlHasProp(node, (const xmlChar *) "transform");
|
||||||
|
if (transform) {
|
||||||
|
const char *s = (const char *) transform->children->content;
|
||||||
|
while (*s) {
|
||||||
|
if (sscanf(s, "matrix(%f,%f,%f,%f,%f,%f) %n",
|
||||||
|
&a, &b, &c, &d, &e, &f, &n) == 6) {
|
||||||
|
;
|
||||||
|
} else if (sscanf(s, "translate(%f,%f) %n",
|
||||||
|
&e, &f, &n) == 2) {
|
||||||
|
a = d = 1;
|
||||||
|
b = c = 0;
|
||||||
|
} else if (sscanf(s, "scale(%f,%f) %n",
|
||||||
|
&a, &d, &n) == 2) {
|
||||||
|
b = c = e = f = 0;
|
||||||
|
s += n;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ctm_a = state->ctm.a * a + state->ctm.c * b;
|
||||||
|
ctm_b = state->ctm.b * a + state->ctm.d * b;
|
||||||
|
ctm_c = state->ctm.a * c + state->ctm.c * d;
|
||||||
|
ctm_d = state->ctm.b * c + state->ctm.d * d;
|
||||||
|
ctm_e = state->ctm.a * e + state->ctm.c * f +
|
||||||
|
state->ctm.e;
|
||||||
|
ctm_f = state->ctm.b * e + state->ctm.d * f +
|
||||||
|
state->ctm.f;
|
||||||
|
state->ctm.a = ctm_a;
|
||||||
|
state->ctm.b = ctm_b;
|
||||||
|
state->ctm.c = ctm_c;
|
||||||
|
state->ctm.d = ctm_d;
|
||||||
|
state->ctm.e = ctm_e;
|
||||||
|
state->ctm.f = ctm_f;
|
||||||
|
s += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a CONTENT_SVG and free all resources it owns.
|
* Destroy a CONTENT_SVG and free all resources it owns.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user