From 5c1f3bd8c899ec79a504d74023143bb4594cfd6c Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sun, 3 Feb 2008 19:11:36 +0000 Subject: Move SVG code into a new library, libsvgtiny. svn path=/trunk/netsurf/; revision=3837 --- image/svg.c | 918 ++++-------------------------------------------------------- image/svg.h | 7 +- 2 files changed, 59 insertions(+), 866 deletions(-) (limited to 'image') diff --git a/image/svg.c b/image/svg.c index 278438c17..9f39cd61f 100644 --- a/image/svg.c +++ b/image/svg.c @@ -1,5 +1,5 @@ /* - * Copyright 2007 James Bursa + * Copyright 2007-2008 James Bursa * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -20,77 +20,36 @@ * Content for image/svg (implementation). */ -#define _GNU_SOURCE /* for strndup */ #include -#include -#include -#include -#include -#include #include "utils/config.h" #ifdef WITH_NS_SVG -#include -#include +#include #include "content/content.h" #include "css/css.h" #include "desktop/plotters.h" -#include "desktop/options.h" #include "image/svg.h" -#include "utils/log.h" #include "utils/messages.h" #include "utils/utils.h" -struct svg_redraw_state { - float viewport_width; - float viewport_height; - - /* current transformation matrix */ - struct { - float a, b, c, d, e, f; - } ctm; - - struct css_style style; - - /* paint attributes */ - colour fill; - colour stroke; - int stroke_width; -}; - - -static bool svg_redraw_svg(xmlNode *svg, struct svg_redraw_state state); -static bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state); -static bool svg_redraw_rect(xmlNode *rect, struct svg_redraw_state state); -static bool svg_redraw_circle(xmlNode *circle, struct svg_redraw_state state); -static bool svg_redraw_line(xmlNode *line, struct svg_redraw_state state); -static bool svg_redraw_poly(xmlNode *poly, struct svg_redraw_state state, - bool polygon); -static bool svg_redraw_text(xmlNode *text, struct svg_redraw_state state); -static void svg_parse_position_attributes(const xmlNode *node, - const struct svg_redraw_state state, - float *x, float *y, float *width, float *height); -static float svg_parse_length(const xmlChar *s, int viewport_size, - const struct svg_redraw_state state); -static void svg_parse_paint_attributes(const xmlNode *node, - struct svg_redraw_state *state); -static void svg_parse_color(const char *s, colour *c); -static void svg_parse_font_attributes(const xmlNode *node, - struct svg_redraw_state *state); -static void svg_parse_transform_attributes(xmlNode *node, - struct svg_redraw_state *state); - - /** * Create a CONTENT_SVG. */ bool svg_create(struct content *c, const char *params[]) { - c->data.svg.doc = 0; - c->data.svg.svg = 0; + union content_msg_data msg_data; + + c->data.svg.diagram = svgtiny_create(); + if (!c->data.svg.diagram) + goto no_memory; return true; + +no_memory: + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; } @@ -100,51 +59,13 @@ bool svg_create(struct content *c, const char *params[]) bool svg_convert(struct content *c, int w, int h) { - xmlDoc *document; - xmlNode *svg; - union content_msg_data msg_data; - - /* parse XML to tree */ - document = xmlReadMemory(c->source_data, c->source_size, - c->url, 0, XML_PARSE_NONET | XML_PARSE_COMPACT); - if (!document) { - LOG(("xmlReadMemory failed")); - msg_data.error = messages_get("ParsingFail"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - c->data.svg.doc = document; + assert(c->data.svg.diagram); - /* xmlDebugDumpDocument(stderr, document); */ + svgtiny_parse(c->data.svg.diagram, c->source_data, c->source_size, + c->url, w, h); - /* find root element */ - for (svg = document->children; - svg && svg->type != XML_ELEMENT_NODE; - svg = svg->next) - continue; - if (!svg) { - LOG(("no element in svg")); - msg_data.error = "no element in svg"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - if (strcmp(svg->name, "svg") != 0) { - LOG(("root element is not svg")); - msg_data.error = "root element is not svg"; - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - c->data.svg.svg = svg; - - /* get graphic dimensions */ - struct svg_redraw_state state; - state.viewport_width = w; - state.viewport_height = h; - state.style = css_base_style; - float x, y, width, height; - svg_parse_position_attributes(svg, state, &x, &y, &width, &height); - c->width = width; - c->height = height; + c->width = c->data.svg.diagram->width; + c->height = c->data.svg.diagram->height; /*c->title = malloc(100); if (c->title) @@ -152,6 +73,7 @@ bool svg_convert(struct content *c, int w, int h) width, height, c->source_size);*/ //c->size += ?; c->status = CONTENT_STATUS_DONE; + return true; } @@ -165,776 +87,47 @@ bool svg_redraw(struct content *c, int x, int y, int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale, unsigned long background_colour) { - assert(c->data.svg.svg); - - struct svg_redraw_state state; - - state.viewport_width = width; - state.viewport_height = height; - state.ctm.a = (float) width / (float) c->width; - state.ctm.b = 0; - state.ctm.c = 0; - state.ctm.d = (float) height / (float) c->height; - state.ctm.e = x; - state.ctm.f = y; - state.style = css_base_style; - state.style.font_size.value.length.value = option_font_size * 0.1; - state.fill = 0x000000; - state.stroke = TRANSPARENT; - state.stroke_width = 1; - - return svg_redraw_svg(c->data.svg.svg, state); -} - - -/** - * Redraw a or element node. - */ - -bool svg_redraw_svg(xmlNode *svg, struct svg_redraw_state state) -{ - float x, y, width, height; - - svg_parse_position_attributes(svg, state, &x, &y, &width, &height); - svg_parse_paint_attributes(svg, &state); - svg_parse_font_attributes(svg, &state); - - /* parse viewBox */ - xmlAttr *view_box = xmlHasProp(svg, (const xmlChar *) "viewBox"); - if (view_box) { - const char *s = (const char *) view_box->children->content; - float min_x, min_y, vwidth, vheight; - if (sscanf(s, "%f,%f,%f,%f", - &min_x, &min_y, &vwidth, &vheight) == 4 || - sscanf(s, "%f %f %f %f", - &min_x, &min_y, &vwidth, &vheight) == 4) { - state.ctm.a = (float) state.viewport_width / vwidth; - state.ctm.d = (float) state.viewport_height / vheight; - state.ctm.e += -min_x * state.ctm.a; - state.ctm.f += -min_y * state.ctm.d; - } - } - - svg_parse_transform_attributes(svg, &state); - - for (xmlNode *child = svg->children; child; child = child->next) { - bool ok = true; - - if (child->type == XML_ELEMENT_NODE) { - if (strcmp(child->name, "svg") == 0) - ok = svg_redraw_svg(child, state); - else if (strcmp(child->name, "g") == 0) - ok = svg_redraw_svg(child, state); - else if (strcmp(child->name, "a") == 0) - ok = svg_redraw_svg(child, state); - else if (strcmp(child->name, "path") == 0) - ok = svg_redraw_path(child, state); - else if (strcmp(child->name, "rect") == 0) - ok = svg_redraw_rect(child, state); - else if (strcmp(child->name, "circle") == 0) - ok = svg_redraw_circle(child, state); - else if (strcmp(child->name, "line") == 0) - ok = svg_redraw_line(child, state); - else if (strcmp(child->name, "polyline") == 0) - ok = svg_redraw_poly(child, state, false); - else if (strcmp(child->name, "polygon") == 0) - ok = svg_redraw_poly(child, state, true); - else if (strcmp(child->name, "text") == 0) - ok = svg_redraw_text(child, state); - } - - if (!ok) - return false; - } - - return true; -} - - -/** - * Redraw a element node. - * - * http://www.w3.org/TR/SVG11/paths#PathElement - */ - -bool svg_redraw_path(xmlNode *path, struct svg_redraw_state state) -{ - char *s, *path_d; - - svg_parse_paint_attributes(path, &state); - svg_parse_transform_attributes(path, &state); - - /* read d attribute */ - s = path_d = (char *) xmlGetProp(path, (const xmlChar *) "d"); - if (!s) { - LOG(("path missing d attribute")); - return false; - } - - /* allocate space for path: it will never have more elements than d */ - float *p = malloc(sizeof p[0] * strlen(s)); - if (!p) { - LOG(("out of memory")); - return false; - } - - /* parse d and build path */ - for (unsigned int i = 0; s[i]; i++) - if (s[i] == ',') - s[i] = ' '; - unsigned int i = 0; - float last_x = 0, last_y = 0; - float last_cubic_x = 0, last_cubic_y = 0; - float last_quad_x = 0, last_quad_y = 0; - while (*s) { - char command[2]; - int plot_command; - float x, y, x1, y1, x2, y2; - int n; - - /* moveto (M, m), lineto (L, l) (2 arguments) */ - if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) { - /*LOG(("moveto or lineto"));*/ - if (*command == 'M' || *command == 'm') - plot_command = PLOTTER_PATH_MOVE; - else - plot_command = PLOTTER_PATH_LINE; - do { - p[i++] = plot_command; - if ('a' <= *command) { - x += last_x; - y += last_y; - } - p[i++] = last_cubic_x = last_quad_x = last_x - = x; - p[i++] = last_cubic_y = last_quad_y = last_y - = y; - s += n; - plot_command = PLOTTER_PATH_LINE; - } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2); - - /* closepath (Z, z) (no arguments) */ - } else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) { - /*LOG(("closepath"));*/ - p[i++] = PLOTTER_PATH_CLOSE; - s += n; - - /* horizontal lineto (H, h) (1 argument) */ - } else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) { - /*LOG(("horizontal lineto"));*/ - do { - p[i++] = PLOTTER_PATH_LINE; - if (*command == 'h') - x += last_x; - p[i++] = last_cubic_x = last_quad_x = last_x - = x; - p[i++] = last_cubic_y = last_quad_y = last_y; - s += n; - } while (sscanf(s, "%f %n", &x, &n) == 1); - - /* vertical lineto (V, v) (1 argument) */ - } else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) { - /*LOG(("vertical lineto"));*/ - do { - p[i++] = PLOTTER_PATH_LINE; - if (*command == 'v') - y += last_y; - p[i++] = last_cubic_x = last_quad_x = last_x; - p[i++] = last_cubic_y = last_quad_y = last_y - = y; - s += n; - } while (sscanf(s, "%f %n", &x, &n) == 1); - - /* curveto (C, c) (6 arguments) */ - } else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command, - &x1, &y1, &x2, &y2, &x, &y, &n) == 7) { - /*LOG(("curveto"));*/ - do { - p[i++] = PLOTTER_PATH_BEZIER; - if (*command == 'c') { - x1 += last_x; - y1 += last_y; - x2 += last_x; - y2 += last_y; - x += last_x; - y += last_y; - } - p[i++] = x1; - p[i++] = y1; - p[i++] = last_cubic_x = x2; - p[i++] = last_cubic_y = y2; - p[i++] = last_quad_x = last_x = x; - p[i++] = last_quad_y = last_y = y; - s += n; - } while (sscanf(s, "%f %f %f %f %f %f %n", - &x1, &y1, &x2, &y2, &x, &y, &n) == 6); - - /* shorthand/smooth curveto (S, s) (4 arguments) */ - } else if (sscanf(s, " %1[Ss] %f %f %f %f %n", command, - &x2, &y2, &x, &y, &n) == 5) { - /*LOG(("shorthand/smooth curveto"));*/ - do { - p[i++] = PLOTTER_PATH_BEZIER; - x1 = last_x + (last_x - last_cubic_x); - y1 = last_y + (last_y - last_cubic_y); - if (*command == 's') { - x2 += last_x; - y2 += last_y; - x += last_x; - y += last_y; - } - p[i++] = x1; - p[i++] = y1; - p[i++] = last_cubic_x = x2; - p[i++] = last_cubic_y = y2; - p[i++] = last_quad_x = last_x = x; - p[i++] = last_quad_y = last_y = y; - s += n; - } while (sscanf(s, "%f %f %f %f %n", - &x2, &y2, &x, &y, &n) == 4); - - /* quadratic Bezier curveto (Q, q) (4 arguments) */ - } else if (sscanf(s, " %1[Qq] %f %f %f %f %n", command, - &x1, &y1, &x, &y, &n) == 5) { - /*LOG(("quadratic Bezier curveto"));*/ - do { - p[i++] = PLOTTER_PATH_BEZIER; - last_quad_x = x1; - last_quad_y = y1; - if (*command == 'q') { - x1 += last_x; - y1 += last_y; - x += last_x; - y += last_y; - } - p[i++] = 1./3 * last_x + 2./3 * x1; - p[i++] = 1./3 * last_y + 2./3 * y1; - p[i++] = 2./3 * x1 + 1./3 * x; - p[i++] = 2./3 * y1 + 1./3 * y; - p[i++] = last_cubic_x = last_x = x; - p[i++] = last_cubic_y = last_y = y; - s += n; - } while (sscanf(s, "%f %f %f %f %n", - &x1, &y1, &x, &y, &n) == 4); - - /* shorthand/smooth quadratic Bezier curveto (T, t) - (2 arguments) */ - } else if (sscanf(s, " %1[Tt] %f %f %n", command, - &x, &y, &n) == 3) { - /*LOG(("shorthand/smooth quadratic Bezier curveto"));*/ - do { - p[i++] = PLOTTER_PATH_BEZIER; - x1 = last_x + (last_x - last_quad_x); - y1 = last_y + (last_y - last_quad_y); - last_quad_x = x1; - last_quad_y = y1; - if (*command == 't') { - x1 += last_x; - y1 += last_y; - x += last_x; - y += last_y; - } - p[i++] = 1./3 * last_x + 2./3 * x1; - p[i++] = 1./3 * last_y + 2./3 * y1; - p[i++] = 2./3 * x1 + 1./3 * x; - p[i++] = 2./3 * y1 + 1./3 * y; - p[i++] = last_cubic_x = last_x = x; - p[i++] = last_cubic_y = last_y = y; - s += n; - } while (sscanf(s, "%f %f %n", - &x, &y, &n) == 2); - - } else { - LOG(("parse failed at \"%s\"", s)); - break; - } - } - - xmlFree(path_d); - - /*LOG(("path:")); - for (unsigned int j = 0; j != i; j++) { - LOG((" %f", p[j])); - }*/ - - bool ok = plot.path(p, i, state.fill, state.stroke_width, state.stroke, - &state.ctm.a); - - free(p); - - return ok; -} - - -/** - * Redraw a element node. - * - * http://www.w3.org/TR/SVG11/shapes#RectElement - */ - -bool svg_redraw_rect(xmlNode *rect, struct svg_redraw_state state) -{ - float x, y, width, height; - - svg_parse_position_attributes(rect, state, - &x, &y, &width, &height); - svg_parse_paint_attributes(rect, &state); - svg_parse_transform_attributes(rect, &state); - - float p[] = { PLOTTER_PATH_MOVE, x, y, - PLOTTER_PATH_LINE, x + width, y, - PLOTTER_PATH_LINE, x + width, y + height, - PLOTTER_PATH_LINE, x, y + height, - PLOTTER_PATH_CLOSE }; - - return plot.path(p, sizeof p / sizeof p[0], state.fill, - state.stroke_width, state.stroke, &state.ctm.a); -} - - -/** - * Redraw a element node. - */ - -bool svg_redraw_circle(xmlNode *circle, struct svg_redraw_state state) -{ - float x = 0, y = 0, r = 0; - - for (xmlAttr *attr = circle->properties; attr; attr = attr->next) { - if (strcmp(attr->name, "cx") == 0) - x = svg_parse_length(attr->children->content, - state.viewport_width, state); - else if (strcmp(attr->name, "cy") == 0) - y = svg_parse_length(attr->children->content, - state.viewport_height, state); - else if (strcmp(attr->name, "r") == 0) - r = svg_parse_length(attr->children->content, - state.viewport_width, state); - } - svg_parse_paint_attributes(circle, &state); - svg_parse_transform_attributes(circle, &state); - - int px = state.ctm.a * x + state.ctm.c * y + state.ctm.e; - int py = state.ctm.b * x + state.ctm.d * y + state.ctm.f; - int pr = r * state.ctm.a; - - if (state.fill != TRANSPARENT) - if (!plot.disc(px, py, pr, state.fill, true)) - return false; - - if (state.stroke != TRANSPARENT) - if (!plot.disc(px, py, pr, state.stroke, false)) - return false; - - return true; -} - - -/** - * Redraw a element node. - */ - -bool svg_redraw_line(xmlNode *line, struct svg_redraw_state state) -{ - float x1 = 0, y1 = 0, x2 = 0, y2 = 0; - - for (xmlAttr *attr = line->properties; attr; attr = attr->next) { - if (strcmp(attr->name, "x1") == 0) - x1 = svg_parse_length(attr->children->content, - state.viewport_width, state); - else if (strcmp(attr->name, "y1") == 0) - y1 = svg_parse_length(attr->children->content, - state.viewport_height, state); - else if (strcmp(attr->name, "x2") == 0) - x2 = svg_parse_length(attr->children->content, - state.viewport_width, state); - else if (strcmp(attr->name, "y2") == 0) - y2 = svg_parse_length(attr->children->content, - state.viewport_height, state); - } - svg_parse_paint_attributes(line, &state); - svg_parse_transform_attributes(line, &state); - - int px1 = state.ctm.a * x1 + state.ctm.c * y1 + state.ctm.e; - int py1 = state.ctm.b * x1 + state.ctm.d * y1 + state.ctm.f; - int px2 = state.ctm.a * x2 + state.ctm.c * y2 + state.ctm.e; - int py2 = state.ctm.b * x2 + state.ctm.d * y2 + state.ctm.f; - - return plot.line(px1, py1, px2, py2, state.stroke_width, state.stroke, - false, false); -} - - -/** - * Redraw a or element node. - * - * http://www.w3.org/TR/SVG11/shapes#PolylineElement - * http://www.w3.org/TR/SVG11/shapes#PolygonElement - */ - -bool svg_redraw_poly(xmlNode *poly, struct svg_redraw_state state, - bool polygon) -{ - char *s, *points; - - svg_parse_paint_attributes(poly, &state); - svg_parse_transform_attributes(poly, &state); - - /* read d attribute */ - s = points = (char *) xmlGetProp(poly, (const xmlChar *) "points"); - if (!s) { - LOG(("poly missing d attribute")); - return false; - } - - /* allocate space for path: it will never have more elements than s */ - float *p = malloc(sizeof p[0] * strlen(s)); - if (!p) { - LOG(("out of memory")); - return false; - } - - /* parse s and build path */ - for (unsigned int i = 0; s[i]; i++) - if (s[i] == ',') - s[i] = ' '; - unsigned int i = 0; - while (*s) { - float x, y; - int n; - - if (sscanf(s, "%f %f %n", &x, &y, &n) == 2) { - if (i == 0) - p[i++] = PLOTTER_PATH_MOVE; - else - p[i++] = PLOTTER_PATH_LINE; - p[i++] = x; - p[i++] = y; - s += n; - } else { - break; - } - } - if (polygon) - p[i++] = PLOTTER_PATH_CLOSE; - - xmlFree(points); - - bool ok = plot.path(p, i, state.fill, state.stroke_width, state.stroke, - &state.ctm.a); - - free(p); - - return ok; -} - - -/** - * Redraw a or element node. - */ - -bool svg_redraw_text(xmlNode *text, struct svg_redraw_state state) -{ - float x, y, width, height; - - svg_parse_position_attributes(text, state, - &x, &y, &width, &height); - svg_parse_font_attributes(text, &state); - svg_parse_transform_attributes(text, &state); - - int px = state.ctm.a * x + state.ctm.c * y + state.ctm.e; - int py = state.ctm.b * x + state.ctm.d * y + state.ctm.f; -/* state.ctm.e = px - state.origin_x; */ -/* state.ctm.f = py - state.origin_y; */ - - struct css_style style = state.style; - style.font_size.value.length.value *= state.ctm.a; - - for (xmlNode *child = text->children; child; child = child->next) { - bool ok = true; - - if (child->type == XML_TEXT_NODE) { + float transform[6]; + struct svgtiny_diagram *diagram = c->data.svg.diagram; + bool ok; + int px, py; + + assert(diagram); + + transform[0] = (float) width / (float) c->width; + transform[1] = 0; + transform[2] = 0; + transform[3] = (float) height / (float) c->height; + transform[4] = x; + transform[5] = y; + + for (unsigned int i = 0; i != diagram->shape_count; i++) { + if (diagram->shape[i].path) { + ok = plot.path(diagram->shape[i].path, + diagram->shape[i].path_length, + diagram->shape[i].fill, + diagram->shape[i].stroke_width, + diagram->shape[i].stroke, + transform); + if (!ok) + return false; + + } else if (diagram->shape[i].text) { + px = transform[0] * diagram->shape[i].text_x + + transform[2] * diagram->shape[i].text_y + + transform[4]; + py = transform[1] * diagram->shape[i].text_x + + transform[3] * diagram->shape[i].text_y + + transform[5]; ok = plot.text(px, py, &css_base_style, - child->content, strlen(child->content), + diagram->shape[i].text, + strlen(diagram->shape[i].text), 0xffffff, 0x000000); - } else if (child->type == XML_ELEMENT_NODE && - strcmp(child->name, "tspan") == 0) { - ok = svg_redraw_text(child, state); - } - - if (!ok) - return false; - } - - return true; -} - - -/** - * Parse x, y, width, and height attributes, if present. - */ - -void svg_parse_position_attributes(const xmlNode *node, - const struct svg_redraw_state state, - float *x, float *y, float *width, float *height) -{ - *x = 0; - *y = 0; - *width = state.viewport_width; - *height = state.viewport_height; - - for (xmlAttr *attr = node->properties; attr; attr = attr->next) { - if (strcmp(attr->name, "x") == 0) - *x = svg_parse_length(attr->children->content, - state.viewport_width, state); - else if (strcmp(attr->name, "y") == 0) - *y = svg_parse_length(attr->children->content, - state.viewport_height, state); - else if (strcmp(attr->name, "width") == 0) - *width = svg_parse_length(attr->children->content, - state.viewport_width, state); - else if (strcmp(attr->name, "height") == 0) - *height = svg_parse_length(attr->children->content, - state.viewport_height, state); - } -} - - -/** - * Parse a length as a number of pixels. - */ - -float svg_parse_length(const xmlChar *s, int viewport_size, - const struct svg_redraw_state state) -{ - int num_length = strspn(s, "0123456789+-."); - const xmlChar *unit = s + num_length; - float n = atof((const char *) s); - float font_size = css_len2px(&state.style.font_size.value.length, 0); - - if (unit[0] == 0) { - return n; - } else if (unit[0] == '%') { - return n / 100.0 * viewport_size; - } else if (unit[0] == 'e' && unit[1] == 'm') { - return n * font_size; - } else if (unit[0] == 'e' && unit[1] == 'x') { - return n / 2.0 * font_size; - } else if (unit[0] == 'p' && unit[1] == 'x') { - return n; - } else if (unit[0] == 'p' && unit[1] == 't') { - return n * 1.25; - } else if (unit[0] == 'p' && unit[1] == 'c') { - return n * 15.0; - } else if (unit[0] == 'm' && unit[1] == 'm') { - return n * 3.543307; - } else if (unit[0] == 'c' && unit[1] == 'm') { - return n * 35.43307; - } else if (unit[0] == 'i' && unit[1] == 'n') { - return n * 90; - } - - return 0; -} - - -/** - * Parse paint attributes, if present. - */ - -void svg_parse_paint_attributes(const xmlNode *node, - struct svg_redraw_state *state) -{ - for (const xmlAttr *attr = node->properties; attr; attr = attr->next) { - if (strcmp(attr->name, "fill") == 0) - svg_parse_color((const char *) attr->children->content, - &state->fill); - else if (strcmp(attr->name, "stroke") == 0) - svg_parse_color((const char *) attr->children->content, - &state->stroke); - else if (strcmp(attr->name, "stroke-width") == 0) - state->stroke_width = svg_parse_length( - attr->children->content, - 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); - } - } - } -} - - -/** - * Parse a colour. - */ - -void svg_parse_color(const char *s, colour *c) -{ - unsigned int r, g, b; - float rf, gf, bf; - size_t len = strlen(s); - - if (len == 4 && s[0] == '#') { - if (sscanf(s + 1, "%1x%1x%1x", &r, &g, &b) == 3) - *c = (b << 20) | (b << 16) | - (g << 12) | (g << 8) | - (r << 4) | r; - } else if (len == 7 && s[0] == '#') { - if (sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3) - *c = (b << 16) | (g << 8) | r; - } else if (10 <= len && s[0] == 'r' && s[1] == 'g' && s[2] == 'b' && - s[3] == '(' && s[len - 1] == ')') { - if (sscanf(s + 4, "%i,%i,%i", &r, &g, &b) == 3) - *c = (b << 16) | (g << 8) | r; - else if (sscanf(s + 4, "%f%%,%f%%,%f%%", &rf, &gf, &bf) == 3) { - b = bf * 255 / 100; - g = gf * 255 / 100; - r = rf * 255 / 100; - *c = (b << 16) | (g << 8) | r; - } - } else if (len == 4 && strcmp(s, "none") == 0) { - *c = TRANSPARENT; - } else { - colour named = named_colour(s); - if (named != CSS_COLOR_NONE) - *c = named; - } -} - - -/** - * Parse font attributes, if present. - */ - -void svg_parse_font_attributes(const xmlNode *node, - struct svg_redraw_state *state) -{ - for (const xmlAttr *attr = node->properties; attr; attr = attr->next) { - if (strcmp(attr->name, "font-size") == 0) { - /*if (css_parse_length( - (const char *) attr->children->content, - &state->style.font_size.value.length, - true, true)) { - state->style.font_size.size = - CSS_FONT_SIZE_LENGTH; - }*/ } } -} - -/** - * Parse transform attributes, if present. - * - * http://www.w3.org/TR/SVG11/coords#TransformAttribute - */ - -void svg_parse_transform_attributes(xmlNode *node, - struct svg_redraw_state *state) -{ - char *transform, *s; - float a, b, c, d, e, f; - float ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f; - float angle, x, y; - int n; - - /* parse transform */ - s = transform = (char *) xmlGetProp(node, - (const xmlChar *) "transform"); - if (transform) { - for (unsigned int i = 0; transform[i]; i++) - if (transform[i] == ',') - transform[i] = ' '; - - while (*s) { - a = d = 1; - b = c = 0; - e = f = 0; - 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) - ; - else if (sscanf(s, "translate (%f) %n", - &e, &n) == 1) - ; - else if (sscanf(s, "scale (%f %f) %n", - &a, &d, &n) == 2) - ; - else if (sscanf(s, "scale (%f) %n", - &a, &n) == 1) - d = a; - else if (sscanf(s, "rotate (%f %f %f) %n", - &angle, &x, &y, &n) == 3) { - angle = -angle / 180 * M_PI; - a = cos(angle); - b = sin(angle); - c = -sin(angle); - d = cos(angle); - e = -x * cos(angle) + y * sin(angle) + x; - f = -x * sin(angle) - y * cos(angle) + y; - } else if (sscanf(s, "rotate (%f) %n", - &angle, &n) == 1) { - angle = -angle / 180 * M_PI; - a = cos(angle); - b = sin(angle); - c = -sin(angle); - d = cos(angle); - } else if (sscanf(s, "skewX (%f) %n", - &angle, &n) == 1) { - angle = angle / 180 * M_PI; - c = tan(angle); - } else if (sscanf(s, "skewY (%f) %n", - &angle, &n) == 1) { - angle = angle / 180 * M_PI; - b = tan(angle); - } 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; - } - - xmlFree(transform); - } + return true; } @@ -944,8 +137,9 @@ void svg_parse_transform_attributes(xmlNode *node, void svg_destroy(struct content *c) { - if (c->data.svg.doc) - xmlFreeDoc(c->data.svg.doc); + if (c->data.svg.diagram) + svgtiny_free(c->data.svg.diagram); } + #endif /* WITH_NS_SVG */ diff --git a/image/svg.h b/image/svg.h index 9544dd9dd..00b628b80 100644 --- a/image/svg.h +++ b/image/svg.h @@ -1,5 +1,5 @@ /* - * Copyright 2007 James Bursa + * Copyright 2007-2008 James Bursa * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -24,13 +24,12 @@ #define _NETSURF_IMAGE_SVG_H_ #include -#include struct content; +struct svgtiny_diagram; struct content_svg_data { - xmlDoc *doc; - xmlNode *svg; + struct svgtiny_diagram *diagram; }; bool svg_create(struct content *c, const char *params[]); -- cgit v1.2.3