]> gitweb.michael.orlitzky.com - libsvgtiny.git/blobdiff - src/svgtiny_gradient.c
prevent division by zero for gradient with no points and add test
[libsvgtiny.git] / src / svgtiny_gradient.c
index 002c322a526262c6576d5fc631683bcd21e10912..c36df3207675aed084a8357706ef06efdf55d0bb 100644 (file)
@@ -31,10 +31,12 @@ static void svgtiny_invert_matrix(float *m, float *inv);
 void svgtiny_find_gradient(const char *id, struct svgtiny_parse_state *state)
 {
        dom_element *gradient;
-       dom_string *id_str;
+       dom_string *id_str, *name;
        dom_exception exc;
 
+       #ifdef GRADIENT_DEBUG
        fprintf(stderr, "svgtiny_find_gradient: id \"%s\"\n", id);
+       #endif
 
        state->linear_gradient_stop_count = 0;
        if (state->gradient_x1 != NULL)
@@ -57,33 +59,37 @@ void svgtiny_find_gradient(const char *id, struct svgtiny_parse_state *state)
        state->gradient_transform.e = 0;
        state->gradient_transform.f = 0;
        
-       exc = dom_string_create_interned((const uint8_t *) id, strlen(id),
-                                        &id_str);
+       exc = dom_string_create_interned((const uint8_t *) id,
+                       strlen(id), &id_str);
        if (exc != DOM_NO_ERR)
                return;
        
        exc = dom_document_get_element_by_id(state->document, id_str,
                                             &gradient);
        dom_string_unref(id_str);
-       if (exc != DOM_NO_ERR)
-               return;
-
-       if (gradient == NULL) {
+       if (exc != DOM_NO_ERR || gradient == NULL) {
+               #ifdef GRADIENT_DEBUG
                fprintf(stderr, "gradient \"%s\" not found\n", id);
+               #endif
                return;
        }
        
-       exc = dom_node_get_node_name(gradient, &id_str);
+       exc = dom_node_get_node_name(gradient, &name);
        if (exc != DOM_NO_ERR) {
                dom_node_unref(gradient);
                return;
        }
        
-       if (dom_string_isequal(id_str, state->interned_linearGradient))
+       if (dom_string_isequal(name, state->interned_linearGradient))
                svgtiny_parse_linear_gradient(gradient, state);
        
-       dom_string_unref(id_str);
        dom_node_unref(gradient);
+       dom_string_unref(name);
+
+       #ifdef GRADIENT_DEBUG
+       fprintf(stderr, "linear_gradient_stop_count %i\n",
+                       state->linear_gradient_stop_count);
+       #endif
 }
 
 
@@ -162,8 +168,10 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
                }
                svgtiny_parse_transform(s, &a, &b, &c, &d, &e, &f);
                free(s);
+               #ifdef GRADIENT_DEBUG
                fprintf(stderr, "transform %g %g %g %g %g %g\n",
                        a, b, c, d, e, f);
+               #endif
                state->gradient_transform.a = a;
                state->gradient_transform.b = b;
                state->gradient_transform.c = c;
@@ -237,7 +245,9 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
                                dom_string_unref(attr);
                        }
                        if (offset != -1 && color != svgtiny_TRANSPARENT) {
+                               #ifdef GRADIENT_DEBUG
                                fprintf(stderr, "stop %g %x\n", offset, color);
+                               #endif
                                state->gradient_stop[i].offset = offset;
                                state->gradient_stop[i].color = color;
                                i++;
@@ -390,16 +400,17 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
 
        /* invert gradient transform for applying to vertices */
        svgtiny_invert_matrix(&state->gradient_transform.a, trans);
+       #ifdef GRADIENT_DEBUG
        fprintf(stderr, "inverse transform %g %g %g %g %g %g\n",
                        trans[0], trans[1], trans[2], trans[3],
                        trans[4], trans[5]);
+       #endif
 
        /* compute points on the path for triangle vertices */
        /* r, r0, r1 are distance along gradient vector */
        gradient_norm_squared = gradient_dx * gradient_dx +
                                      gradient_dy * gradient_dy;
-       pts = svgtiny_list_create(
-                       sizeof (struct grad_point));
+       pts = svgtiny_list_create(sizeof (struct grad_point));
        if (!pts)
                return svgtiny_OUT_OF_MEMORY;
        for (j = 0; j != n; ) {
@@ -462,11 +473,19 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                                gradient_norm_squared;
 
                /* determine steps from change in r */
-               steps = ceilf(fabsf(r1 - r0) / 0.05);
+
+               if(isnan(r0) || isnan(r1)) {
+                       steps = 1;
+               } else {
+                       steps = ceilf(fabsf(r1 - r0) / 0.05);
+               }
+
                if (steps == 0)
                        steps = 1;
+               #ifdef GRADIENT_DEBUG
                fprintf(stderr, "r0 %g, r1 %g, steps %i\n",
                                r0, r1, steps);
+               #endif
 
                /* loop through intermediate points */
                for (z = 1; z != steps; z++) {
@@ -491,7 +510,9 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                        r = ((x_trans - gradient_x0) * gradient_dx +
                                        (y_trans - gradient_y0) * gradient_dy) /
                                        gradient_norm_squared;
+                       #ifdef GRADIENT_DEBUG
                        fprintf(stderr, "(%g %g [%g]) ", x, y, r);
+                       #endif
                        point = svgtiny_list_push(pts);
                        if (!point) {
                                svgtiny_list_free(pts);
@@ -505,15 +526,26 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                                min_pt = svgtiny_list_size(pts) - 1;
                        }
                }
+               #ifdef GRADIENT_DEBUG
                fprintf(stderr, "\n");
+               #endif
 
                /* next segment start point is this segment end point */
                x0 = x1;
                y0 = y1;
        }
+       #ifdef GRADIENT_DEBUG
        fprintf(stderr, "pts size %i, min_pt %i, min_r %.3f\n",
                        svgtiny_list_size(pts), min_pt, min_r);
+       #endif
+
+        /* There must be at least a single point for the gradient */
+        if (svgtiny_list_size(pts) == 0) {
+            svgtiny_list_free(pts);
 
+            return svgtiny_OK;
+        }
+        
        /* render triangles */
        stop_count = state->linear_gradient_stop_count;
        assert(2 <= stop_count);
@@ -632,7 +664,7 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
 
        /* render triangle vertices with r values for debugging */
        #ifdef GRADIENT_DEBUG
-       for (unsigned int i = 0; i != pts->size; i++) {
+       for (unsigned int i = 0; i != svgtiny_list_size(pts); i++) {
                struct grad_point *point = svgtiny_list_get(pts, i);
                struct svgtiny_shape *shape = svgtiny_add_shape(state);
                if (!shape)