+ return err;
+}
+
+
+/**
+ * Parse an <ellipse> element node.
+ */
+
+svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
+ struct svgtiny_parse_state state)
+{
+ svgtiny_code err;
+ float x = 0, y = 0, rx = -1, ry = -1;
+ float *p;
+ dom_string *attr;
+ dom_exception exc;
+
+ 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) {
+ x = svgtiny_parse_length(attr, state.viewport_width, state);
+ }
+ 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) {
+ y = svgtiny_parse_length(attr, state.viewport_height, state);
+ }
+ 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) {
+ rx = svgtiny_parse_length(attr, state.viewport_width, state);
+ }
+ dom_string_unref(attr);
+
+ exc = dom_element_get_attribute(ellipse, state.interned_ry, &attr);
+ if (exc != DOM_NO_ERR) {
+ svgtiny_cleanup_state_local(&state);
+ return svgtiny_LIBDOM_ERROR;
+ }
+ if (attr != NULL) {
+ ry = svgtiny_parse_length(attr, state.viewport_width, state);
+ }
+ dom_string_unref(attr);
+
+ svgtiny_parse_paint_attributes(ellipse, &state);
+ svgtiny_parse_transform_attributes(ellipse, &state);
+
+ if (rx < 0 || ry < 0) {
+ state.diagram->error_line = -1; /* ellipse->line; */
+ state.diagram->error_message = "ellipse: rx or ry missing "
+ "or negative";
+ svgtiny_cleanup_state_local(&state);
+ return svgtiny_SVG_ERROR;
+ }
+ if (rx == 0 || ry == 0) {
+ svgtiny_cleanup_state_local(&state);
+ return svgtiny_OK;
+ }
+
+ p = malloc(32 * sizeof p[0]);
+ if (!p) {
+ svgtiny_cleanup_state_local(&state);
+ return svgtiny_OUT_OF_MEMORY;
+ }
+
+ p[0] = svgtiny_PATH_MOVE;
+ p[1] = x + rx;
+ p[2] = y;
+ p[3] = svgtiny_PATH_BEZIER;
+ p[4] = x + rx;
+ p[5] = y + ry * KAPPA;
+ p[6] = x + rx * KAPPA;
+ p[7] = y + ry;
+ p[8] = x;
+ p[9] = y + ry;
+ p[10] = svgtiny_PATH_BEZIER;
+ p[11] = x - rx * KAPPA;
+ p[12] = y + ry;
+ p[13] = x - rx;
+ p[14] = y + ry * KAPPA;
+ p[15] = x - rx;
+ p[16] = y;
+ p[17] = svgtiny_PATH_BEZIER;
+ p[18] = x - rx;
+ p[19] = y - ry * KAPPA;
+ p[20] = x - rx * KAPPA;
+ p[21] = y - ry;
+ p[22] = x;
+ p[23] = y - ry;
+ p[24] = svgtiny_PATH_BEZIER;
+ p[25] = x + rx * KAPPA;
+ p[26] = y - ry;
+ p[27] = x + rx;
+ p[28] = y - ry * KAPPA;
+ p[29] = x + rx;
+ p[30] = y;
+ p[31] = svgtiny_PATH_CLOSE;
+
+ err = svgtiny_add_path(p, 32, &state);
+
+ svgtiny_cleanup_state_local(&state);
+
+ return err;