]> gitweb.michael.orlitzky.com - libsvgtiny.git/blobdiff - src/svgtiny.c
src/svgtiny.c: implement composition of parent styles
[libsvgtiny.git] / src / svgtiny.c
index a70be0f50643530e86d9639204cc64b4569e3764..91ce4396799e7f96714fdb7e4114a6e23f2fa600 100644 (file)
@@ -71,7 +71,7 @@ static void svgtiny_parse_font_attributes(dom_element *node,
                struct svgtiny_parse_state *state);
 static void svgtiny_parse_transform_attributes(dom_element *node,
                struct svgtiny_parse_state *state);
-static void svgtiny_parse_styles(dom_element *node,
+static css_select_results *svgtiny_parse_styles(dom_element *node,
                struct svgtiny_parse_state *state);
 static svgtiny_code svgtiny_add_path(float *p, unsigned int n,
                struct svgtiny_parse_state *state);
@@ -982,13 +982,14 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg,
        dom_string *view_box;
        dom_element *child;
        dom_exception exc;
+       css_select_results *styles;
 
        svgtiny_setup_state_local(&state);
 
        svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height);
        svgtiny_parse_paint_attributes(svg, &state);
        svgtiny_parse_font_attributes(svg, &state);
-       svgtiny_parse_styles(svg, &state);
+       styles = svgtiny_parse_styles(svg, &state);
 
        exc = dom_element_get_attribute(svg, state.interned_viewBox,
                                        &view_box);
@@ -1026,6 +1027,14 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg,
                dom_node_type nodetype;
                svgtiny_code code = svgtiny_OK;
 
+               /* Before we descend to one of my child elements, set
+                * the "parent style" to my style. */
+               if (styles) {
+                       /* For now at least, the root element won't
+                        * have any styles; hence the null check. */
+                       state.parent_style = styles->styles[CSS_PSEUDO_ELEMENT_NONE];
+               }
+
                exc = dom_node_get_node_type(child, &nodetype);
                if (exc != DOM_NO_ERR) {
                        dom_node_unref(child);
@@ -1089,6 +1098,9 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg,
                child = next;
        }
 
+       /* Hoping that destroying "styles" destroys state.parent_style
+        * as well. */
+       css_select_results_destroy(styles);
        svgtiny_cleanup_state_local(&state);
        return svgtiny_OK;
 }
@@ -1120,7 +1132,7 @@ svgtiny_code svgtiny_parse_path(dom_element *path,
 
        svgtiny_parse_paint_attributes(path, &state);
        svgtiny_parse_transform_attributes(path, &state);
-       svgtiny_parse_styles(path, &state);
+       css_select_results_destroy(svgtiny_parse_styles(path, &state));
 
        /* read d attribute */
        exc = dom_element_get_attribute(path, state.interned_d, &path_d_str);
@@ -1476,7 +1488,7 @@ svgtiny_code svgtiny_parse_rect(dom_element *rect,
                        &x, &y, &width, &height);
        svgtiny_parse_paint_attributes(rect, &state);
        svgtiny_parse_transform_attributes(rect, &state);
-       svgtiny_parse_styles(rect, &state);
+       css_select_results_destroy(svgtiny_parse_styles(rect, &state));
 
        p = malloc(13 * sizeof p[0]);
        if (!p) {
@@ -1553,7 +1565,7 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle,
 
        svgtiny_parse_paint_attributes(circle, &state);
        svgtiny_parse_transform_attributes(circle, &state);
-       svgtiny_parse_styles(circle, &state);
+       css_select_results_destroy(svgtiny_parse_styles(circle, &state));
 
        if (r < 0) {
                state.diagram->error_line = -1; /* circle->line; */
@@ -1670,7 +1682,7 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
 
        svgtiny_parse_paint_attributes(ellipse, &state);
        svgtiny_parse_transform_attributes(ellipse, &state);
-       svgtiny_parse_styles(ellipse, &state);
+       css_select_results_destroy(svgtiny_parse_styles(ellipse, &state));
 
        if (rx < 0 || ry < 0) {
                state.diagram->error_line = -1; /* ellipse->line; */
@@ -1788,7 +1800,7 @@ svgtiny_code svgtiny_parse_line(dom_element *line,
 
        svgtiny_parse_paint_attributes(line, &state);
        svgtiny_parse_transform_attributes(line, &state);
-       svgtiny_parse_styles(line, &state);
+       css_select_results_destroy(svgtiny_parse_styles(line, &state));
 
        p = malloc(7 * sizeof p[0]);
        if (!p) {
@@ -1833,7 +1845,7 @@ svgtiny_code svgtiny_parse_poly(dom_element *poly,
 
        svgtiny_parse_paint_attributes(poly, &state);
        svgtiny_parse_transform_attributes(poly, &state);
-       svgtiny_parse_styles(poly, &state);
+       css_select_results_destroy(svgtiny_parse_styles(poly, &state));
 
        exc = dom_element_get_attribute(poly, state.interned_points,
                                        &points_str);
@@ -2290,8 +2302,8 @@ void svgtiny_parse_transform_attributes(dom_element *node,
  * styles that we support and set the corresponding fields in the
  * parser state.
  */
-void svgtiny_parse_styles(dom_element *node,
-               struct svgtiny_parse_state *state)
+css_select_results *svgtiny_parse_styles(dom_element *node,
+                       struct svgtiny_parse_state *state)
 {
        css_error code;
        uint8_t   fill_opacity_type;
@@ -2310,6 +2322,9 @@ void svgtiny_parse_styles(dom_element *node,
         * safely destroy it later even if we never populated it. */
        css_select_results *styles = NULL;
 
+       /* The result of composing this node's styles with its
+        * parent's styles. */
+       css_computed_style *composed = NULL;
 
        dom_exception exc;
        dom_string *attr;
@@ -2355,20 +2370,39 @@ void svgtiny_parse_styles(dom_element *node,
                return NULL;
        }
 
+       if (state->parent_style != NULL) {
+               code = css_computed_style_compose(
+                               state->parent_style,
+                               styles->styles[CSS_PSEUDO_ELEMENT_NONE],
+                               &state->unit_ctx,
+                               &composed);
+
+               if (code != CSS_OK || composed == NULL) {
+                       /* This function promises to return a
+                        * fully-composed set of styles, so if
+                        * we can't do that, we should fail. */
+                       css_select_results_destroy(styles);
+                       return NULL;
+               }
+
+               /* Replace my original computed styles with the
+                * composed ones */
+               css_computed_style_destroy(
+                               styles->styles[CSS_PSEUDO_ELEMENT_NONE]);
+               styles->styles[CSS_PSEUDO_ELEMENT_NONE] = composed;
+       }
+
        fill_opacity_type = css_computed_fill_opacity(
                                styles->styles[CSS_PSEUDO_ELEMENT_NONE],
                                &fill_opacity);
        stroke_opacity_type = css_computed_stroke_opacity(
                                styles->styles[CSS_PSEUDO_ELEMENT_NONE],
                                &stroke_opacity);
-       css_select_results_destroy(styles);
 
-       if (fill_opacity_type == CSS_FILL_OPACITY_SET) {
-               state->fill_opacity = FIXTOFLT(fill_opacity);
-       }
-       if (stroke_opacity_type == CSS_STROKE_OPACITY_SET) {
-               state->stroke_opacity = FIXTOFLT(stroke_opacity);
-       }
+       state->fill_opacity = FIXTOFLT(fill_opacity);
+       state->stroke_opacity = FIXTOFLT(stroke_opacity);
+
+       return styles;
 }
 
 /**