+}
+
+
+/**
+ * convert an svg path arc to a bezier curve
+ *
+ * This function perfoms a transform on the nine arc parameters
+ * (coordinate pairs for start and end together with the radii of the
+ * elipse, the rotation angle and which of the four arcs to draw)
+ * which generates the parameters (coordinate pairs for start,
+ * end and their control points) for a set of up to four bezier curves.
+ *
+ * Obviously the start and end coordinates are not altered between
+ * representations so the aim is to calculate the coordinate pairs for
+ * the bezier control points.
+ *
+ * \param bzpoints the array to fill with bezier curves
+ * \return the number of bezier segments generated or -1 for a line
+ */
+static int
+svgarc_to_bezier(float start_x,
+ float start_y,
+ float end_x,
+ float end_y,
+ float rx,
+ float ry,
+ float angle,
+ bool largearc,
+ bool sweep,
+ double *bzpoints)
+{
+ double radangle; /* normalised elipsis rotation angle in radians */
+ double rx_sq; /* x radius squared */
+ double ry_sq; /* y radius squared */
+ double x1, y1; /* rotated midpoint vector */
+ double x1_sq, y1_sq; /* x1 vector squared */
+ double cx1,cy1; /* transformed circle center */
+ double cx,cy; /* circle center */
+ double start, extent;
+ int bzsegments;
+
+ if ((start_x == end_x) && (start_y == end_y)) {
+ /*
+ * if the start and end coordinates are the same the
+ * svg spec says this is equivalent to having no segment
+ * at all
+ */
+ return 0;
+ }
+
+ if ((rx == 0) || (ry == 0)) {
+ /*
+ * if either radii is zero the specified behaviour is a line
+ */
+ return -1;
+ }
+
+ /* obtain the absolute values of the radii */
+ rx = fabsf(rx);
+ ry = fabsf(ry);
+
+ /* convert normalised angle to radians */
+ radangle = degToRad(fmod(angle, 360.0));
+
+ /* step 1 */
+ /* x1,x2 is the midpoint vector rotated to remove the arc angle */
+ rotate_midpoint_vector(start_x, start_y, end_x, end_y, radangle, &x1, &y1);
+
+ /* step 2 */
+ /* get squared x1 values */
+ x1_sq = x1 * x1;
+ y1_sq = y1 * y1;
+
+ /* ensure radii are correctly scaled */
+ ensure_radii_scale(x1_sq, y1_sq, &rx, &ry, &rx_sq, &ry_sq);
+
+ /* compute the transformed centre point */
+ compute_transformed_centre_point(largearc == sweep?-1:1,
+ rx, ry,
+ rx_sq, ry_sq,
+ x1, y1,
+ x1_sq, y1_sq,
+ &cx1, &cy1);
+
+ /* step 3 */
+ /* get the untransformed centre point */
+ compute_centre_point(start_x, start_y,
+ end_x, end_y,
+ cx1, cy1,
+ radangle,
+ &cx, &cy);
+
+ /* step 4 */
+ /* compute anglestart and extent */
+ compute_angle_start_extent(rx,ry,
+ x1,y1,
+ cx1, cy1,
+ &start, &extent);
+
+ /* extent of 0 is a straight line */
+ if (extent == 0) {
+ return -1;
+ }
+
+ /* take account of sweep */
+ if (!sweep && extent > 0) {
+ extent -= TAU;
+ } else if (sweep && extent < 0) {
+ extent += TAU;
+ }
+
+ /* normalise start and extent */
+ extent = fmod(extent, TAU);
+ start = fmod(start, TAU);
+
+ /* convert the arc to unit circle bezier curves */
+ bzsegments = circle_arc_to_bezier(start, extent, bzpoints);
+
+ /* transform the bezier curves */
+ scale_rotate_translate_points(rx, ry,
+ radangle,
+ cx, cy,
+ bzsegments * 6,
+ bzpoints);
+
+ return bzsegments;
+}
+
+
+/**
+ * Call this to ref the strings in a gradient state.
+ */
+static void svgtiny_grad_string_ref(struct svgtiny_parse_state_gradient *grad)
+{
+ if (grad->gradient_x1 != NULL) {
+ dom_string_ref(grad->gradient_x1);
+ }
+ if (grad->gradient_y1 != NULL) {
+ dom_string_ref(grad->gradient_y1);
+ }
+ if (grad->gradient_x2 != NULL) {
+ dom_string_ref(grad->gradient_x2);
+ }
+ if (grad->gradient_y2 != NULL) {
+ dom_string_ref(grad->gradient_y2);