]> gitweb.michael.orlitzky.com - libsvgtiny.git/commitdiff
Improve attribute parsing with operation tables
authorVincent Sanders <vince@kyllikki.org>
Wed, 10 Jul 2024 09:15:53 +0000 (10:15 +0100)
committerVincent Sanders <vince@kyllikki.org>
Wed, 10 Jul 2024 23:48:41 +0000 (00:48 +0100)
src/svgtiny.c
src/svgtiny_internal.h
src/svgtiny_parse.c

index 2e3d7044740fbf96cc7c07d4963007387e948b9b..b2171275905cf5a9bd0c1d6883a7e9542f01025e 100644 (file)
@@ -53,7 +53,7 @@ static svgtiny_code svgtiny_parse_poly(dom_element *poly,
 static svgtiny_code svgtiny_parse_text(dom_element *text,
                struct svgtiny_parse_state state);
 static void svgtiny_parse_position_attributes(dom_element *node,
-               const struct svgtiny_parse_state state,
+               struct svgtiny_parse_state state,
                float *x, float *y, float *width, float *height);
 static void svgtiny_parse_paint_attributes(dom_element *node,
                struct svgtiny_parse_state *state);
@@ -1273,49 +1273,34 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle,
        svgtiny_code err;
        float x = 0, y = 0, r = -1;
        float *p;
-       dom_string *attr;
-       dom_exception exc;
+       struct svgtiny_parse_internal_operation ops[] = {
+               {
+                       state.interned_cx,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       &x
+               }, {
+                       state.interned_cy,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       &y
+               }, {
+                       state.interned_r,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       &r
+               }, {
+                       NULL, SVGTIOP_NONE, NULL, NULL
+               },
+       };
 
        svgtiny_setup_state_local(&state);
 
-       exc = dom_element_get_attribute(circle, state.interned_cx, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &x);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(circle, state.interned_cy, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_height,
-                                    &y);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(circle, state.interned_r, &attr);
-       if (exc != DOM_NO_ERR) {
+       err = svgtiny_parse_attributes(circle, &state, ops);
+       if (err != svgtiny_OK) {
                svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
+               return err;
        }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &r);
-       }
-       dom_string_unref(attr);
 
        svgtiny_parse_paint_attributes(circle, &state);
        svgtiny_parse_transform_attributes(circle, &state);
@@ -1388,62 +1373,39 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
        svgtiny_code err;
        float x = 0, y = 0, rx = -1, ry = -1;
        float *p;
-       dom_string *attr;
-       dom_exception exc;
+       struct svgtiny_parse_internal_operation ops[] = {
+               {
+                       state.interned_cx,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       &x
+               }, {
+                       state.interned_cy,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       &y
+               }, {
+                       state.interned_rx,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       &rx
+               }, {
+                       state.interned_ry,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       &ry
+               }, {
+                       NULL, SVGTIOP_NONE, NULL, NULL
+               },
+       };
 
        svgtiny_setup_state_local(&state);
 
-       exc = dom_element_get_attribute(ellipse, state.interned_cx, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &x);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(ellipse, state.interned_cy, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_height,
-                                    &y);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(ellipse, state.interned_rx, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &rx);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(ellipse, state.interned_ry, &attr);
-       if (exc != DOM_NO_ERR) {
+       err = svgtiny_parse_attributes(ellipse, &state, ops);
+       if (err != svgtiny_OK) {
                svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &ry);
+               return err;
        }
-       dom_string_unref(attr);
 
        svgtiny_parse_paint_attributes(ellipse, &state);
        svgtiny_parse_transform_attributes(ellipse, &state);
@@ -1517,62 +1479,39 @@ svgtiny_code svgtiny_parse_line(dom_element *line,
        svgtiny_code err;
        float x1 = 0, y1 = 0, x2 = 0, y2 = 0;
        float *p;
-       dom_string *attr;
-       dom_exception exc;
+       struct svgtiny_parse_internal_operation ops[] = {
+               {
+                       state.interned_x1,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       &x1
+               }, {
+                       state.interned_y1,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       &y1
+               }, {
+                       state.interned_x2,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       &x2
+               }, {
+                       state.interned_y2,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       &y2
+               }, {
+                       NULL, SVGTIOP_NONE, NULL, NULL
+               },
+       };
 
        svgtiny_setup_state_local(&state);
 
-       exc = dom_element_get_attribute(line, state.interned_x1, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &x1);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(line, state.interned_y1, &attr);
-       if (exc != DOM_NO_ERR) {
+       err = svgtiny_parse_attributes(line, &state, ops);
+       if (err != svgtiny_OK) {
                svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
+               return err;
        }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_height,
-                                    &y1);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(line, state.interned_x2, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    &x2);
-       }
-       dom_string_unref(attr);
-
-       exc = dom_element_get_attribute(line, state.interned_y2, &attr);
-       if (exc != DOM_NO_ERR) {
-               svgtiny_cleanup_state_local(&state);
-               return svgtiny_LIBDOM_ERROR;
-       }
-       if (attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_height,
-                                    &y2);
-       }
-       dom_string_unref(attr);
 
        svgtiny_parse_paint_attributes(line, &state);
        svgtiny_parse_transform_attributes(line, &state);
@@ -1778,52 +1717,45 @@ svgtiny_code svgtiny_parse_text(dom_element *text,
  */
 
 void svgtiny_parse_position_attributes(dom_element *node,
-               const struct svgtiny_parse_state state,
+               struct svgtiny_parse_state state,
                float *x, float *y, float *width, float *height)
 {
-       dom_string *attr;
-       dom_exception exc;
+       struct svgtiny_parse_internal_operation styles[] = {
+               {
+                       /* x */
+                       state.interned_x,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       x
+               },{
+                       /* y */
+                       state.interned_y,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       y
+               },{
+                       /* width */
+                       state.interned_width,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_width,
+                       width
+               },{
+                       /* height */
+                       state.interned_height,
+                       SVGTIOP_LENGTH,
+                       &state.viewport_height,
+                       height
+               },{
+                       NULL, SVGTIOP_NONE, NULL, NULL
+               },
+       };
 
        *x = 0;
        *y = 0;
        *width = state.viewport_width;
        *height = state.viewport_height;
 
-       exc = dom_element_get_attribute(node, state.interned_x, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    x);
-               dom_string_unref(attr);
-       }
-
-       exc = dom_element_get_attribute(node, state.interned_y, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_height,
-                                    y);
-               dom_string_unref(attr);
-       }
-
-       exc = dom_element_get_attribute(node, state.interned_width, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_width,
-                                    width);
-               dom_string_unref(attr);
-       }
-
-       exc = dom_element_get_attribute(node, state.interned_height, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state.viewport_height,
-                                    height);
-               dom_string_unref(attr);
-       }
+       svgtiny_parse_attributes(node, &state, styles);
 }
 
 
@@ -1833,72 +1765,32 @@ void svgtiny_parse_position_attributes(dom_element *node,
 void svgtiny_parse_paint_attributes(dom_element *node,
                struct svgtiny_parse_state *state)
 {
-       dom_string *attr;
-       dom_exception exc;
-
-       /* fill color */
-       exc = dom_element_get_attribute(node, state->interned_fill, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_paint(dom_string_data(attr),
-                                   dom_string_byte_length(attr),
-                                   &state->fill_grad,
-                                   state,
-                                   &state->fill);
-               dom_string_unref(attr);
-       }
-
-       /* stroke color */
-       exc = dom_element_get_attribute(node, state->interned_stroke, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_paint(dom_string_data(attr),
-                                   dom_string_byte_length(attr),
-                                   &state->stroke_grad,
-                                   state,
-                                   &state->stroke);
-               dom_string_unref(attr);
-       }
-
-       /* stroke width */
-       exc = dom_element_get_attribute(node, state->interned_stroke_width, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               float stroke_width;
-               svgtiny_parse_length(dom_string_data(attr),
-                                    dom_string_byte_length(attr),
-                                    state->viewport_width,
-                                    &stroke_width);
-               state->stroke_width = stroke_width;
-               dom_string_unref(attr);
-       }
-
-       /* style attribute */
-       exc = dom_element_get_attribute(node, state->interned_style, &attr);
-       if (exc == DOM_NO_ERR && attr != NULL) {
-               struct svgtiny_parse_inline_style_op styles[]={
-                       {
-                               state->interned_fill,
-                               ISTYLEOP_PAINT,
-                               &state->fill_grad,
-                               &state->fill
-                       }, {
-                               state->interned_stroke,
-                               ISTYLEOP_PAINT,
-                               &state->stroke_grad,
-                               &state->stroke
-                       }, {
-                               state->interned_stroke_width,
-                               ISTYLEOP_INTLENGTH,
-                               &state->viewport_width,
-                               &state->stroke_width
-                       },{
-                               NULL, ISTYLEOP_NONE, NULL, NULL
-                       },
-               };
-               svgtiny_parse_inline_style(dom_string_data(attr),
-                                          dom_string_byte_length(attr),
-                                          state,
-                                          styles);
-               dom_string_unref(attr);
-       }
+       struct svgtiny_parse_internal_operation ops[] = {
+               {
+                       /* fill color */
+                       state->interned_fill,
+                       SVGTIOP_PAINT,
+                       &state->fill_grad,
+                       &state->fill
+               }, {
+                       /* stroke color */
+                       state->interned_stroke,
+                       SVGTIOP_PAINT,
+                       &state->stroke_grad,
+                       &state->stroke
+               }, {
+                       /* stroke width */
+                       state->interned_stroke_width,
+                       SVGTIOP_INTLENGTH,
+                       &state->viewport_width,
+                       &state->stroke_width
+               },{
+                       NULL, SVGTIOP_NONE, NULL, NULL
+               },
+       };
+
+       svgtiny_parse_attributes(node, state, ops);
+       svgtiny_parse_inline_style(node, state, ops);
 }
 
 
index 20680fbefc93c7b5b9f09efbef3dec31ee8a1d80..d2ba4d377162e4abc06a06d573bab70cae78842d 100644 (file)
@@ -73,20 +73,19 @@ struct svgtiny_parse_state {
 
 struct svgtiny_list;
 
-enum svgtiny_parse_inline_style_operation {
-       ISTYLEOP_NONE,
-       ISTYLEOP_PAINT,
-       ISTYLEOP_COLOR,
-       ISTYLEOP_LENGTH,
-       ISTYLEOP_INTLENGTH,
-};
-
 /**
  * control structure for inline style parse
  */
-struct svgtiny_parse_inline_style_op {
+struct svgtiny_parse_internal_operation {
        dom_string *key;
-       enum svgtiny_parse_inline_style_operation operation;
+       enum {
+               SVGTIOP_NONE,
+               SVGTIOP_PAINT,
+               SVGTIOP_COLOR,
+               SVGTIOP_LENGTH,
+               SVGTIOP_INTLENGTH,
+               SVGTIOP_OFFSET,
+       } operation;
        void *param;
        void *value;
 };
@@ -110,18 +109,17 @@ svgtiny_code svgtiny_parse_length(const char *text, size_t textlen,
                int viewport_size, float *length);
 svgtiny_code svgtiny_parse_transform(const char *text, size_t textlen,
                struct svgtiny_transformation_matrix *tm);
-svgtiny_code svgtiny_parse_paint(const char *text, size_t textlen,
-               struct svgtiny_parse_state_gradient *grad,
-               struct svgtiny_parse_state *state,
-               svgtiny_colour *c);
 svgtiny_code svgtiny_parse_color(const char *text, size_t textlen,
                svgtiny_colour *c);
 svgtiny_code svgtiny_parse_viewbox(const char *text, size_t textlen,
                float viewport_width, float viewport_height,
                struct svgtiny_transformation_matrix *tm);
-svgtiny_code svgtiny_parse_inline_style(const char *text, size_t textlen,
+svgtiny_code svgtiny_parse_inline_style(dom_element *node,
+               struct svgtiny_parse_state *state,
+               struct svgtiny_parse_internal_operation *ops);
+svgtiny_code svgtiny_parse_attributes(dom_element *node,
                struct svgtiny_parse_state *state,
-               struct svgtiny_parse_inline_style_op *styles);
+               struct svgtiny_parse_internal_operation *ops);
 
 /* svgtiny_gradient.c */
 svgtiny_code svgtiny_find_gradient(const char *id,
index c4882009b36326a28218f4d5aece44ab998acf9f..e2af7fe2cde3c2def03c3586211cc254b9c3cdb1 100644 (file)
@@ -856,22 +856,195 @@ parse_paint_url(const char **cursorout,
 
        /* find and update gradient */
        res = svgtiny_find_gradient(idstart, idend - idstart, grad, state);
+       if (res == svgtiny_OK) {
+               *c = svgtiny_LINEAR_GRADIENT;
+       }
+
+       return res;
+}
+
+
+/**
+ * Parse a paint.
+ *
+ * https://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint
+ * https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
+ *
+ */
+static svgtiny_code
+svgtiny_parse_paint(const char *text,
+                   size_t textlen,
+                   struct svgtiny_parse_state_gradient *grad,
+                   struct svgtiny_parse_state *state,
+                   svgtiny_colour *c)
+{
+       const char *cursor = text; /* cursor */
+       const char *textend = text+textlen;
+       svgtiny_code res;
 
+       advance_whitespace(&cursor, textend);
+
+       if (((textend - cursor) == 4) &&
+           cursor[0] == 'n' &&
+           cursor[1] == 'o' &&
+           cursor[2] == 'n' &&
+           cursor[3] == 'e') {
+               *c = svgtiny_TRANSPARENT;
+               return svgtiny_OK;
+       }
+
+       /* attempt to parse element as a paint url */
+       res = parse_paint_url(&cursor, textend, grad, state, c);
        if (res == svgtiny_OK) {
-               /* only set the color if the gradient was processed ok */
-               if (grad->linear_gradient_stop_count == 0) {
-                       *c = svgtiny_TRANSPARENT;
-               } else if (grad->linear_gradient_stop_count == 1) {
-                       *c = grad->gradient_stop[0].color;
-               } else {
-                       *c = svgtiny_LINEAR_GRADIENT;
-               }
+               return res;
        }
 
+       return svgtiny_parse_color(cursor, textend - cursor, c);
+}
+
+
+/**
+ * parse an offset
+ */
+static svgtiny_code
+svgtiny_parse_offset(const char *text, size_t textlen, float *offset)
+{
+       svgtiny_code err;
+       float number;
+       const char *numend;
+
+       numend = text + textlen;
+       err = parse_number(text, &numend, &number);
+       if (err != svgtiny_OK) {
+               return err;
+       }
+       if ((numend < (text + textlen)) && (*numend == '%')) {
+               number /= 100.0;
+       }
+       /* ensure value between 0 and 1 */
+       if (number < 0) {
+               number = 0;
+       }
+       if (number > 1.0) {
+               number = 1.0;
+       }
+       *offset = number;
+       return svgtiny_OK;
+}
+
+
+/**
+ * dispatch parse operation
+ */
+static inline svgtiny_code
+dispatch_op(const char *value,
+           size_t value_len,
+           struct svgtiny_parse_state *state,
+           struct svgtiny_parse_internal_operation *styleop)
+{
+       float parse_len;
+       svgtiny_code res = svgtiny_OK;
+
+       switch (styleop->operation) {
+       case SVGTIOP_NONE:
+               res = svgtiny_SVG_ERROR;
+               break;
+
+       case SVGTIOP_PAINT:
+               res = svgtiny_parse_paint(value,
+                                   value_len,
+                                   styleop->param,
+                                   state,
+                                   styleop->value);
+               break;
+
+       case SVGTIOP_COLOR:
+               res = svgtiny_parse_color(value, value_len, styleop->value);
+               break;
+
+       case SVGTIOP_LENGTH:
+               res = svgtiny_parse_length(value,
+                                    value_len,
+                                    *((int *)styleop->param),
+                                    styleop->value);
+               break;
+
+       case SVGTIOP_INTLENGTH:
+               res = svgtiny_parse_length(value,
+                                    value_len,
+                                    *((int *)styleop->param),
+                                    &parse_len);
+               *((int *)styleop->value) = parse_len;
+               break;
+
+       case SVGTIOP_OFFSET:
+               res = svgtiny_parse_offset(value, value_len, styleop->value);
+               break;
+       }
        return res;
 }
 
 
+/**
+ * parse a declaration in a style
+ *
+ * https://www.w3.org/TR/CSS21/syndata.html#declaration
+ *
+ * \param declaration The declaration without any preceeding space
+ * \param end The end of the declaration string
+ * \param state parse state to pass on
+ * \param styleops The table of style operations to apply
+ *
+ * declaration is "<property name> : <property value>"
+ */
+static inline svgtiny_code
+parse_declaration(const char *declaration,
+                 const char *end,
+                 struct svgtiny_parse_state *state,
+                 struct svgtiny_parse_internal_operation *styleops)
+{
+       const char *cursor = declaration; /* text cursor */
+       size_t key_len; /* key length */
+       struct svgtiny_parse_internal_operation *styleop;
+
+       /* declaration must be at least 3 characters long (ie "a:b") */
+       if ((end - declaration) < 3) {
+               return svgtiny_SVG_ERROR;
+       }
+
+       /* find end of key */
+       advance_property_name(&cursor, end);
+
+       if ((cursor - declaration) < 1) {
+               /* no key */
+               return svgtiny_SVG_ERROR;
+       }
+
+       key_len = cursor - declaration;
+
+       advance_whitespace(&cursor, end);
+
+       if ((cursor >= end) || (*cursor != ':')) {
+               /* no colon */
+               return svgtiny_SVG_ERROR;
+       }
+       cursor++; /* advance over colon */
+
+       advance_whitespace(&cursor, end);
+
+       /* search style operations for a match */
+       for (styleop = styleops; styleop->key != NULL; styleop++) {
+               if ((dom_string_byte_length(styleop->key) == key_len) &&
+                   (memcmp(declaration, dom_string_data(styleop->key), key_len) == 0)) {
+                       /* found the operation, stop iterating */
+                       return dispatch_op(cursor, end - cursor, state, styleop);
+               }
+       }
+
+       return svgtiny_OK;
+}
+
+
 /**
  * parse text points into path points
  *
@@ -1136,43 +1309,6 @@ transform_parse_complete:
 }
 
 
-/**
- * Parse a paint.
- *
- * https://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint
- * https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
- *
- */
-svgtiny_code
-svgtiny_parse_paint(const char *text,
-                   size_t textlen,
-                   struct svgtiny_parse_state_gradient *grad,
-                   struct svgtiny_parse_state *state,
-                   svgtiny_colour *c)
-{
-       const char *cursor = text; /* cursor */
-       const char *textend = text+textlen;
-       svgtiny_code res;
-
-       advance_whitespace(&cursor, textend);
-
-       if (((textend - cursor) == 4) &&
-           cursor[0] == 'n' &&
-           cursor[1] == 'o' &&
-           cursor[2] == 'n' &&
-           cursor[3] == 'e') {
-               *c = svgtiny_TRANSPARENT;
-               return svgtiny_OK;
-       }
-
-       /* attempt to parse element as a paint url */
-       res = parse_paint_url(&cursor, textend, grad, state, c);
-       if (res == svgtiny_OK) {
-               return res;
-       }
-
-       return svgtiny_parse_color(cursor, textend - cursor, c);
-}
 
 
 /**
@@ -1279,124 +1415,75 @@ svgtiny_parse_viewbox(const char *text,
        return svgtiny_OK;
 }
 
+
 /**
- * parse a declaration in a style
- *
- * https://www.w3.org/TR/CSS21/syndata.html#declaration
- *
- * \param declaration The declaration without any preceeding space
- * \param end The end of the declaration string
- * \param state parse state to pass on
- * \param styleops The table of style operations to apply
- *
- * declaration is "<property name> : <property value>"
+ * parse an inline style
  */
-static inline svgtiny_code
-parse_declaration(const char *declaration,
-                 const char *end,
-                 struct svgtiny_parse_state *state,
-                 struct svgtiny_parse_inline_style_op *styleops)
+svgtiny_code
+svgtiny_parse_inline_style(dom_element *node,
+                          struct svgtiny_parse_state *state,
+                          struct svgtiny_parse_internal_operation *ops)
 {
-       const char *cursor = declaration; /* text cursor */
-       size_t key_len; /* key length */
-       struct svgtiny_parse_inline_style_op *styleop;
-
-       /* declaration must be at least 3 characters long (ie "a:b") */
-       if ((end - declaration) < 3) {
-               return svgtiny_SVG_ERROR;
-       }
-
-       /* find end of key */
-       advance_property_name(&cursor, end);
+       const char *cursor; /* text cursor */
+       const char *textend;
+       const char *declaration_start;
+       dom_string *attr;
+       dom_exception exc;
 
-       if ((cursor - declaration) < 1) {
-               /* no key */
-               return svgtiny_SVG_ERROR;
+       /* style attribute */
+       exc = dom_element_get_attribute(node, state->interned_style, &attr);
+       if (exc != DOM_NO_ERR) {
+               return svgtiny_LIBDOM_ERROR;
        }
-
-       key_len = cursor - declaration;
-
-       advance_whitespace(&cursor, end);
-
-       if ((cursor >= end) || (*cursor != ':')) {
-               /* no colon */
-               return svgtiny_SVG_ERROR;
+       if (attr == NULL) {
+               /* no style attribute */
+               return svgtiny_OK;
        }
-       cursor++; /* advance over colon */
-
-       advance_whitespace(&cursor, end);
-
-       /* search style operations for a match */
-       for (styleop = styleops; styleop->key != NULL; styleop++) {
-               if ((dom_string_byte_length(styleop->key) == key_len) &&
-                   (memcmp(declaration, dom_string_data(styleop->key), key_len) == 0)) {
-                       float parse_len;
-
-                       switch (styleop->operation) {
-                       case ISTYLEOP_PAINT:
-                               svgtiny_parse_paint(cursor,
-                                                   end - cursor,
-                                                   styleop->param,
-                                                   state,
-                                                   styleop->value);
-                               break;
+       cursor = dom_string_data(attr);
+       textend = cursor + dom_string_byte_length(attr);
 
-                       case ISTYLEOP_COLOR:
-                               svgtiny_parse_color(cursor,
-                                                   end - cursor,
-                                                   styleop->value);
-                               break;
-
-                       case ISTYLEOP_LENGTH:
-                               svgtiny_parse_length(cursor,
-                                                    end - cursor,
-                                                    *((int *)styleop->param),
-                                                    styleop->value);
-                               break;
-
-                       case ISTYLEOP_INTLENGTH:
-                               svgtiny_parse_length(cursor,
-                                                    end - cursor,
-                                                    *((int *)styleop->param),
-                                                    &parse_len);
-                               *((int *)styleop->value) = parse_len;
-                               break;
-
-                       default:
+       while (cursor < textend) {
+               advance_whitespace(&cursor, textend);
+               declaration_start = cursor;
+               while (cursor < textend) {
+                       if ((*cursor == ';') &&
+                           (*(cursor - 1) != '\\')) {
                                break;
                        }
-                       break; /* found the operation, stop iterating */
+                       cursor++;
                }
+               parse_declaration(declaration_start, cursor, state, ops);
+               cursor++; /* skip semicolon */
        }
-
+       dom_string_unref(attr);
        return svgtiny_OK;
 }
 
+
 /**
- * parse an inline style
+ * parse attributes controled by operation table
  */
 svgtiny_code
-svgtiny_parse_inline_style(const char *text,
-                          size_t textlen,
-                          struct svgtiny_parse_state *state,
-                          struct svgtiny_parse_inline_style_op *styles)
+svgtiny_parse_attributes(dom_element *node,
+                        struct svgtiny_parse_state *state,
+                        struct svgtiny_parse_internal_operation *styleops)
 {
-       const char *cursor = text; /* text cursor */
-       const char *textend = text + textlen;
-       const char *declaration_start;
+       struct svgtiny_parse_internal_operation *styleop;
+       dom_string *attr;
+       dom_exception exc;
 
-       while (cursor < textend) {
-               advance_whitespace(&cursor, textend);
-               declaration_start = cursor;
-               while (cursor < textend) {
-                       if ((*cursor == ';') &&
-                           (*(cursor - 1) != '\\')) {
-                               break;
-                       }
-                       cursor++;
+       for (styleop = styleops; styleop->key != NULL; styleop++) {
+               exc = dom_element_get_attribute(node, styleop->key, &attr);
+               if (exc != DOM_NO_ERR) {
+                       return svgtiny_LIBDOM_ERROR;
+               }
+               if (attr != NULL) {
+                       dispatch_op(dom_string_data(attr),
+                                   dom_string_byte_length(attr),
+                                   state,
+                                   styleop);
+                       dom_string_unref(attr);
                }
-               parse_declaration(declaration_start, cursor, state, styles);
-               cursor++;/* skip semicolon */
        }
        return svgtiny_OK;
 }