From: Vincent Sanders Date: Wed, 10 Jul 2024 09:15:53 +0000 (+0100) Subject: Improve attribute parsing with operation tables X-Git-Url: https://gitweb.michael.orlitzky.com/?a=commitdiff_plain;h=43fd02f4c70f7db1d3b442a854259d260d9f307a;p=libsvgtiny.git Improve attribute parsing with operation tables --- diff --git a/src/svgtiny.c b/src/svgtiny.c index 2e3d704..b217127 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -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); } diff --git a/src/svgtiny_internal.h b/src/svgtiny_internal.h index 20680fb..d2ba4d3 100644 --- a/src/svgtiny_internal.h +++ b/src/svgtiny_internal.h @@ -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, diff --git a/src/svgtiny_parse.c b/src/svgtiny_parse.c index c488200..e2af7fe 100644 --- a/src/svgtiny_parse.c +++ b/src/svgtiny_parse.c @@ -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 " : " + */ +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 " : " + * 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; }