bool html_css_process_link(html_content *htmlc, dom_node *node) { dom_string *rel, *type_attr, *media, *href; struct html_stylesheet *stylesheets; nsurl *joined; dom_exception exc; nserror ns_error; hlcache_child_context child; /* rel=<space separated list, including 'stylesheet'> */ exc = dom_element_get_attribute(node, corestring_dom_rel, &rel); if (exc != DOM_NO_ERR || rel == NULL) return true; if (strcasestr(dom_string_data(rel), "stylesheet") == 0) { dom_string_unref(rel); return true; } else if (strcasestr(dom_string_data(rel), "alternate") != 0) { /* Ignore alternate stylesheets */ dom_string_unref(rel); return true; } dom_string_unref(rel); /* type='text/css' or not present */ exc = dom_element_get_attribute(node, corestring_dom_type, &type_attr); if (exc == DOM_NO_ERR && type_attr != NULL) { if (!dom_string_caseless_lwc_isequal(type_attr, corestring_lwc_text_css)) { dom_string_unref(type_attr); return true; } dom_string_unref(type_attr); } /* media contains 'screen' or 'all' or not present */ exc = dom_element_get_attribute(node, corestring_dom_media, &media); if (exc == DOM_NO_ERR && media != NULL) { if (strcasestr(dom_string_data(media), "screen") == NULL && strcasestr(dom_string_data(media), "all") == NULL) { dom_string_unref(media); return true; } dom_string_unref(media); } /* href='...' */ exc = dom_element_get_attribute(node, corestring_dom_href, &href); if (exc != DOM_NO_ERR || href == NULL) return true; /* TODO: only the first preferred stylesheets (ie. * those with a title attribute) should be loaded * (see HTML4 14.3) */ ns_error = nsurl_join(htmlc->base_url, dom_string_data(href), &joined); if (ns_error != NSERROR_OK) { dom_string_unref(href); goto no_memory; } dom_string_unref(href); LOG("linked stylesheet %i '%s'", htmlc->stylesheet_count, nsurl_access(joined)); /* extend stylesheets array to allow for new sheet */ stylesheets = realloc(htmlc->stylesheets, sizeof(struct html_stylesheet) * (htmlc->stylesheet_count + 1)); if (stylesheets == NULL) { nsurl_unref(joined); ns_error = NSERROR_NOMEM; goto no_memory; } htmlc->stylesheets = stylesheets; htmlc->stylesheets[htmlc->stylesheet_count].node = NULL; htmlc->stylesheets[htmlc->stylesheet_count].modified = false; /* start fetch */ child.charset = htmlc->encoding; child.quirks = htmlc->base.quirks; ns_error = hlcache_handle_retrieve(joined, 0, content_get_url(&htmlc->base), NULL, html_convert_css_callback, htmlc, &child, CONTENT_CSS, &htmlc->stylesheets[htmlc->stylesheet_count].sheet); nsurl_unref(joined); if (ns_error != NSERROR_OK) goto no_memory; htmlc->stylesheet_count++; htmlc->base.active++; LOG("%d fetches active", htmlc->base.active); return true; no_memory: content_broadcast_errorcode(&htmlc->base, ns_error); return false; }
svgtiny_code svgtiny_parse_poly(dom_element *poly, struct svgtiny_parse_state state, bool polygon) { svgtiny_code err; dom_string *points_str; dom_exception exc; char *s, *points; float *p; unsigned int i; svgtiny_setup_state_local(&state); svgtiny_parse_paint_attributes(poly, &state); svgtiny_parse_transform_attributes(poly, &state); exc = dom_element_get_attribute(poly, state.interned_points, &points_str); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (points_str == NULL) { state.diagram->error_line = -1; /* poly->line; */ state.diagram->error_message = "polyline/polygon: missing points attribute"; svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } s = points = strndup(dom_string_data(points_str), dom_string_byte_length(points_str)); dom_string_unref(points_str); /* read points attribute */ if (s == NULL) { svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* allocate space for path: it will never have more elements than s */ p = malloc(sizeof p[0] * strlen(s)); if (!p) { free(points); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* parse s and build path */ for (i = 0; s[i]; i++) if (s[i] == ',') s[i] = ' '; i = 0; while (*s) { float x, y; int n; if (sscanf(s, "%f %f %n", &x, &y, &n) == 2) { if (i == 0) p[i++] = svgtiny_PATH_MOVE; else p[i++] = svgtiny_PATH_LINE; p[i++] = x; p[i++] = y; s += n; } else { break; } } if (polygon) p[i++] = svgtiny_PATH_CLOSE; free(points); err = svgtiny_add_path(p, i, &state); svgtiny_cleanup_state_local(&state); return err; }
static bool save_complete_handle_element(save_complete_ctx *ctx, dom_node *node, save_complete_event_type event_type) { dom_string *name; dom_namednodemap *attrs; const char *name_data; size_t name_len; bool process = true; dom_exception error; ctx->iter_state = STATE_NORMAL; error = dom_node_get_node_name(node, &name); if (error != DOM_NO_ERR) return false; if (name == NULL) return true; name_data = dom_string_data(name); name_len = dom_string_byte_length(name); if (name_len == SLEN("base") && strncasecmp(name_data, "base", name_len) == 0) { /* Elide BASE elements from the output */ process = false; } else if (name_len == SLEN("meta") && strncasecmp(name_data, "meta", name_len) == 0) { /* Don't emit close tags for META elements */ if (event_type == EVENT_LEAVE) { process = false; } else { /* Elide meta charsets */ dom_string *value; error = dom_element_get_attribute(node, corestring_dom_http_equiv, &value); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (value != NULL) { if (dom_string_length(value) == SLEN("Content-Type") && strncasecmp(dom_string_data(value), "Content-Type", SLEN("Content-Type")) == 0) process = false; dom_string_unref(value); } else { bool yes; error = dom_element_has_attribute(node, corestring_dom_charset, &yes); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (yes) process = false; } } } else if (event_type == EVENT_LEAVE && ((name_len == SLEN("link") && strncasecmp(name_data, "link", name_len) == 0))) { /* Don't emit close tags for void elements */ process = false; } if (process == false) { dom_string_unref(name); return true; } fputc('<', ctx->fp); if (event_type == EVENT_LEAVE) fputc('/', ctx->fp); fwrite(name_data, sizeof(*name_data), name_len, ctx->fp); if (event_type == EVENT_ENTER) { error = dom_node_get_attributes(node, &attrs); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (save_complete_handle_attrs(ctx, name, attrs) == false) { dom_namednodemap_unref(attrs); dom_string_unref(name); return false; } dom_namednodemap_unref(attrs); } fputc('>', ctx->fp); /* Rewrite contents of style elements */ if (event_type == EVENT_ENTER && name_len == SLEN("style") && strncasecmp(name_data, "style", name_len) == 0) { dom_string *content; error = dom_node_get_text_content(node, &content); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (content != NULL) { char *rewritten; unsigned long len; /* Rewrite @import rules */ rewritten = save_complete_rewrite_stylesheet_urls( ctx, dom_string_data(content), dom_string_byte_length(content), ctx->base, &len); if (rewritten == NULL) { dom_string_unref(content); dom_string_unref(name); return false; } dom_string_unref(content); fwrite(rewritten, sizeof(*rewritten), len, ctx->fp); free(rewritten); } ctx->iter_state = STATE_IN_STYLE; } else if (event_type == EVENT_ENTER && name_len == SLEN("head") && strncasecmp(name_data, "head", name_len) == 0) { /* If this is a HEAD element, insert a meta charset */ fputs("<META http-equiv=\"Content-Type\" " "content=\"text/html; charset=utf-8\">", ctx->fp); } dom_string_unref(name); return true; }
static void picasa_web_album_load_from_element (DomDomizable *base, DomElement *element) { PicasaWebAlbum *self; DomElement *node; self = PICASA_WEB_ALBUM (base); picasa_web_album_set_id (self, NULL); picasa_web_album_set_title (self, NULL); picasa_web_album_set_summary (self, NULL); picasa_web_album_set_alternate_url (self, NULL); picasa_web_album_set_edit_url (self, NULL); picasa_web_album_set_access (self, NULL); self->n_photos = 0; self->n_photos_remaining = 0; self->used_bytes = 0; picasa_web_album_set_etag (self, dom_element_get_attribute (element, "gd:etag")); for (node = element->first_child; node; node = node->next_sibling) { if (g_strcmp0 (node->tag_name, "gphoto:id") == 0) { picasa_web_album_set_id (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "title") == 0) { picasa_web_album_set_title (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "summary") == 0) { picasa_web_album_set_summary (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "gphoto:location") == 0) { picasa_web_album_set_location (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "link") == 0) { if (g_strcmp0 (dom_element_get_attribute (node, "rel"), "edit") == 0) picasa_web_album_set_edit_url (self, dom_element_get_attribute (node, "href")); else if (g_strcmp0 (dom_element_get_attribute (node, "rel"), "alternate") == 0) picasa_web_album_set_alternate_url (self, dom_element_get_attribute (node, "href")); } else if (g_strcmp0 (node->tag_name, "gphoto:access") == 0) { picasa_web_album_set_access (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "gphoto:numphotos") == 0) { picasa_web_album_set_n_photos (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "gphoto:numphotosremaining") == 0) { picasa_web_album_set_n_photos_remaining (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "gphoto:bytesUsed") == 0) { picasa_web_album_set_used_bytes (self, dom_element_get_inner_text (node)); } else if (g_strcmp0 (node->tag_name, "media:group") == 0) { DomElement *child; for (child = node->first_child; child; child = child->next_sibling) { if (g_strcmp0 (child->tag_name, "media:keywords") == 0) { picasa_web_album_set_keywords (self, dom_element_get_inner_text (child)); break; } } } } }
/** * Extract all imagemaps from a document tree * * \param c The content to extract imagemaps from. * \return false on memory exhaustion, true otherwise */ nserror imagemap_extract(html_content *c) { dom_nodelist *nlist; dom_exception exc; unsigned long mapnr; uint32_t maybe_maps; nserror ret = NSERROR_OK; exc = dom_document_get_elements_by_tag_name(c->document, corestring_dom_map, &nlist); if (exc != DOM_NO_ERR) { return NSERROR_DOM; } exc = dom_nodelist_get_length(nlist, &maybe_maps); if (exc != DOM_NO_ERR) { ret = NSERROR_DOM; goto out_nlist; } for (mapnr = 0; mapnr < maybe_maps; ++mapnr) { dom_node *node; dom_string *name; exc = dom_nodelist_item(nlist, mapnr, &node); if (exc != DOM_NO_ERR) { ret = NSERROR_DOM; goto out_nlist; } exc = dom_element_get_attribute(node, corestring_dom_id, &name); if (exc != DOM_NO_ERR) { dom_node_unref(node); ret = NSERROR_DOM; goto out_nlist; } if (name == NULL) { exc = dom_element_get_attribute(node, corestring_dom_name, &name); if (exc != DOM_NO_ERR) { dom_node_unref(node); ret = NSERROR_DOM; goto out_nlist; } } if (name != NULL) { struct mapentry *entry = NULL; if (imagemap_extract_map(node, c, &entry) == false) { if (entry != NULL) { imagemap_freelist(entry); } dom_string_unref(name); dom_node_unref(node); ret = NSERROR_NOMEM; /** @todo check this */ goto out_nlist; } /* imagemap_extract_map may not extract anything, * so entry can still be NULL here. This isn't an * error as it just means that we've encountered * an incorrectly defined <map>...</map> block */ if ((entry != NULL) && (imagemap_add(c, name, entry) == false)) { imagemap_freelist(entry); dom_string_unref(name); dom_node_unref(node); ret = NSERROR_NOMEM; /** @todo check this */ goto out_nlist; } } dom_string_unref(name); dom_node_unref(node); } out_nlist: dom_nodelist_unref(nlist); return ret; }
void ss__gth_catalog_read_from_doc (GthCatalog *catalog, DomElement *root) { DomElement *node; for (node = root->first_child; node; node = node->next_sibling) { DomElement *child; if (g_strcmp0 (node->tag_name, "slideshow") != 0) continue; g_value_hash_set_boolean (catalog->attributes, "slideshow::personalize", g_strcmp0 (dom_element_get_attribute (node, "personalize"), "true") == 0); g_value_hash_set_boolean (catalog->attributes, "slideshow::automatic", g_strcmp0 (dom_element_get_attribute (node, "automatic"), "true") == 0); g_value_hash_set_boolean (catalog->attributes, "slideshow::wrap-around", g_strcmp0 (dom_element_get_attribute (node, "wrap-around"), "true") == 0); g_value_hash_set_boolean (catalog->attributes, "slideshow::random-order", g_strcmp0 (dom_element_get_attribute (node, "random-order"), "true") == 0); for (child = node->first_child; child; child = child->next_sibling) { if (g_strcmp0 (child->tag_name, "delay") == 0) { int delay; sscanf (dom_element_get_inner_text (child), "%d", &delay); g_value_hash_set_int (catalog->attributes, "slideshow::delay", delay); } else if (g_strcmp0 (child->tag_name, "transition") == 0) { g_value_hash_set_string (catalog->attributes, "slideshow::transition", dom_element_get_inner_text (child)); } else if (g_strcmp0 (child->tag_name, "playlist") == 0) { DomElement *file; GList *audio_files; audio_files = NULL; for (file = child->first_child; file; file = file->next_sibling) { if (g_strcmp0 (file->tag_name, "file") == 0) audio_files = g_list_prepend (audio_files, g_strdup (dom_element_get_attribute (file, "uri"))); } audio_files = g_list_reverse (audio_files); if (audio_files != NULL) { char **audio_files_v; audio_files_v = _g_string_list_to_strv (audio_files); g_value_hash_set_stringv (catalog->attributes, "slideshow::playlist", audio_files_v); g_strfreev (audio_files_v); } else g_value_hash_unset (catalog->attributes, "slideshow::playlist"); _g_string_list_free (audio_files); } } } }
/** * Adds an imagemap entry to the list * * \param c The html content that the imagemap belongs to * \param n The xmlNode representing the entry to add * \param base_url Base URL for resolving relative URLs * \param entry Pointer to list of entries * \param tagtype The type of tag * \return false on memory exhaustion, true otherwise */ static bool imagemap_addtolist(const struct html_content *c, dom_node *n, nsurl *base_url, struct mapentry **entry, dom_string *tagtype) { dom_exception exc; dom_string *href = NULL, *target = NULL, *shape = NULL; dom_string *coords = NULL; struct mapentry *new_map, *temp; bool ret = true; if (dom_string_caseless_isequal(tagtype, corestring_dom_area)) { bool nohref = false; exc = dom_element_has_attribute(n, corestring_dom_nohref, &nohref); if ((exc != DOM_NO_ERR) || nohref) /* Skip <area nohref="anything" /> */ goto ok_out; } exc = dom_element_get_attribute(n, corestring_dom_href, &href); if (exc != DOM_NO_ERR || href == NULL) { /* No href="" attribute, skip this element */ goto ok_out; } exc = dom_element_get_attribute(n, corestring_dom_target, &target); if (exc != DOM_NO_ERR) { goto ok_out; } exc = dom_element_get_attribute(n, corestring_dom_shape, &shape); if (exc != DOM_NO_ERR) { goto ok_out; } /* If there's no shape, we default to rectangles */ if (shape == NULL) shape = dom_string_ref(corestring_dom_rect); if (!dom_string_caseless_lwc_isequal(shape, corestring_lwc_default)) { /* If not 'default' and there's no 'coords' give up */ exc = dom_element_get_attribute(n, corestring_dom_coords, &coords); if (exc != DOM_NO_ERR || coords == NULL) { goto ok_out; } } new_map = calloc(1, sizeof(*new_map)); if (new_map == NULL) { goto bad_out; } if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_rect) || dom_string_caseless_lwc_isequal(shape, corestring_lwc_rectangle)) new_map->type = IMAGEMAP_RECT; else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_circle)) new_map->type = IMAGEMAP_CIRCLE; else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_poly) || dom_string_caseless_lwc_isequal(shape, corestring_lwc_polygon)) new_map->type = IMAGEMAP_POLY; else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_default)) new_map->type = IMAGEMAP_DEFAULT; else goto bad_out; if (box_extract_link(c, href, base_url, &new_map->url) == false) goto bad_out; if (new_map->url == NULL) { /* non-fatal error -> ignore this */ goto ok_free_map_out; } if (target != NULL) { /* Copy target into the map */ new_map->target = malloc(dom_string_byte_length(target) + 1); if (new_map->target == NULL) goto bad_out; /* Safe, but relies on dom_strings being NULL terminated */ /* \todo Do this better */ strcpy(new_map->target, dom_string_data(target)); } if (new_map->type != IMAGEMAP_DEFAULT) { int x, y; float *xcoords, *ycoords; /* coordinates are a comma-separated list of values */ char *val = strtok((char *)dom_string_data(coords), ","); int num = 1; switch (new_map->type) { case IMAGEMAP_RECT: /* (left, top, right, bottom) */ while (val != NULL && num <= 4) { switch (num) { case 1: new_map->bounds.rect.x0 = atoi(val); break; case 2: new_map->bounds.rect.y0 = atoi(val); break; case 3: new_map->bounds.rect.x1 = atoi(val); break; case 4: new_map->bounds.rect.y1 = atoi(val); break; } num++; val = strtok(NULL, ","); } break; case IMAGEMAP_CIRCLE: /* (x, y, radius ) */ while (val != NULL && num <= 3) { switch (num) { case 1: new_map->bounds.circle.x = atoi(val); break; case 2: new_map->bounds.circle.y = atoi(val); break; case 3: new_map->bounds.circle.r = atoi(val); break; } num++; val = strtok(NULL, ","); } break; case IMAGEMAP_POLY: new_map->bounds.poly.xcoords = NULL; new_map->bounds.poly.ycoords = NULL; while (val != NULL) { x = atoi(val); val = strtok(NULL, ","); if (val == NULL) break; y = atoi(val); xcoords = realloc(new_map->bounds.poly.xcoords, num * sizeof(float)); if (xcoords == NULL) { goto bad_out; } new_map->bounds.poly.xcoords = xcoords; ycoords = realloc(new_map->bounds.poly.ycoords, num * sizeof(float)); if (ycoords == NULL) { goto bad_out; } new_map->bounds.poly.ycoords = ycoords; new_map->bounds.poly.xcoords[num - 1] = x; new_map->bounds.poly.ycoords[num - 1] = y; num++; val = strtok(NULL, ","); } new_map->bounds.poly.num = num - 1; break; default: break; } } new_map->next = NULL; if (*entry) { /* add to END of list */ for (temp = (*entry); temp->next != NULL; temp = temp->next) ; temp->next = new_map; } else { (*entry) = new_map; } /* All good, linked in, let's clean up */ goto ok_out; bad_out: ret = false; ok_free_map_out: if (new_map != NULL) { if (new_map->url != NULL) nsurl_unref(new_map->url); if (new_map->type == IMAGEMAP_POLY && new_map->bounds.poly.ycoords != NULL) free(new_map->bounds.poly.ycoords); if (new_map->type == IMAGEMAP_POLY && new_map->bounds.poly.xcoords != NULL) free(new_map->bounds.poly.xcoords); if (new_map->target != NULL) free(new_map->target); free(new_map); } ok_out: if (href != NULL) dom_string_unref(href); if (target != NULL) dom_string_unref(target); if (shape != NULL) dom_string_unref(shape); if (coords != NULL) dom_string_unref(coords); return ret; }
svgtiny_code svgtiny_parse_line(dom_element *line, struct svgtiny_parse_state state) { svgtiny_code err; float x1 = 0, y1 = 0, x2 = 0, y2 = 0; float *p; dom_string *attr; dom_exception exc; 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) { x1 = svgtiny_parse_length(attr, state.viewport_width, state); } dom_string_unref(attr); exc = dom_element_get_attribute(line, state.interned_y1, &attr); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (attr != NULL) { y1 = svgtiny_parse_length(attr, state.viewport_height, state); } 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) { x2 = svgtiny_parse_length(attr, state.viewport_width, state); } 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) { y2 = svgtiny_parse_length(attr, state.viewport_height, state); } dom_string_unref(attr); svgtiny_parse_paint_attributes(line, &state); svgtiny_parse_transform_attributes(line, &state); p = malloc(7 * sizeof p[0]); if (!p) { svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } p[0] = svgtiny_PATH_MOVE; p[1] = x1; p[2] = y1; p[3] = svgtiny_PATH_LINE; p[4] = x2; p[5] = y2; p[6] = svgtiny_PATH_CLOSE; err = svgtiny_add_path(p, 7, &state); svgtiny_cleanup_state_local(&state); return err; }
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; }
svgtiny_code svgtiny_parse_path(dom_element *path, struct svgtiny_parse_state state) { svgtiny_code err; dom_string *path_d_str; dom_exception exc; char *s, *path_d; float *p; unsigned int i; float last_x = 0, last_y = 0; float last_cubic_x = 0, last_cubic_y = 0; float last_quad_x = 0, last_quad_y = 0; svgtiny_setup_state_local(&state); svgtiny_parse_paint_attributes(path, &state); svgtiny_parse_transform_attributes(path, &state); /* read d attribute */ exc = dom_element_get_attribute(path, state.interned_d, &path_d_str); if (exc != DOM_NO_ERR) { state.diagram->error_line = -1; /* path->line; */ state.diagram->error_message = "path: error retrieving d attribute"; svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } if (path_d_str == NULL) { state.diagram->error_line = -1; /* path->line; */ state.diagram->error_message = "path: missing d attribute"; svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } s = path_d = strndup(dom_string_data(path_d_str), dom_string_byte_length(path_d_str)); dom_string_unref(path_d_str); if (s == NULL) { svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* allocate space for path: it will never have more elements than d */ p = malloc(sizeof p[0] * strlen(s)); if (!p) { free(path_d); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* parse d and build path */ for (i = 0; s[i]; i++) if (s[i] == ',') s[i] = ' '; i = 0; while (*s) { char command[2]; int plot_command; float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep; int n; /* moveto (M, m), lineto (L, l) (2 arguments) */ if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) { /*LOG(("moveto or lineto"));*/ if (*command == 'M' || *command == 'm') plot_command = svgtiny_PATH_MOVE; else plot_command = svgtiny_PATH_LINE; do { p[i++] = plot_command; if ('a' <= *command) { x += last_x; y += last_y; } p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y = y; s += n; plot_command = svgtiny_PATH_LINE; } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2); /* closepath (Z, z) (no arguments) */ } else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) { /*LOG(("closepath"));*/ p[i++] = svgtiny_PATH_CLOSE; s += n; /* horizontal lineto (H, h) (1 argument) */ } else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) { /*LOG(("horizontal lineto"));*/ do { p[i++] = svgtiny_PATH_LINE; if (*command == 'h') x += last_x; p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y; s += n; } while (sscanf(s, "%f %n", &x, &n) == 1); /* vertical lineto (V, v) (1 argument) */ } else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) { /*LOG(("vertical lineto"));*/ do { p[i++] = svgtiny_PATH_LINE; if (*command == 'v') y += last_y; p[i++] = last_cubic_x = last_quad_x = last_x; p[i++] = last_cubic_y = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %n", &x, &n) == 1); /* curveto (C, c) (6 arguments) */ } else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command, &x1, &y1, &x2, &y2, &x, &y, &n) == 7) { /*LOG(("curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; if (*command == 'c') { x1 += last_x; y1 += last_y; x2 += last_x; y2 += last_y; x += last_x; y += last_y; } p[i++] = x1; p[i++] = y1; p[i++] = last_cubic_x = x2; p[i++] = last_cubic_y = y2; p[i++] = last_quad_x = last_x = x; p[i++] = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %f %f %n", &x1, &y1, &x2, &y2, &x, &y, &n) == 6); /* shorthand/smooth curveto (S, s) (4 arguments) */ } else if (sscanf(s, " %1[Ss] %f %f %f %f %n", command, &x2, &y2, &x, &y, &n) == 5) { /*LOG(("shorthand/smooth curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_cubic_x); y1 = last_y + (last_y - last_cubic_y); if (*command == 's') { x2 += last_x; y2 += last_y; x += last_x; y += last_y; } p[i++] = x1; p[i++] = y1; p[i++] = last_cubic_x = x2; p[i++] = last_cubic_y = y2; p[i++] = last_quad_x = last_x = x; p[i++] = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %n", &x2, &y2, &x, &y, &n) == 4); /* quadratic Bezier curveto (Q, q) (4 arguments) */ } else if (sscanf(s, " %1[Qq] %f %f %f %f %n", command, &x1, &y1, &x, &y, &n) == 5) { /*LOG(("quadratic Bezier curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; last_quad_x = x1; last_quad_y = y1; if (*command == 'q') { x1 += last_x; y1 += last_y; x += last_x; y += last_y; } p[i++] = 1./3 * last_x + 2./3 * x1; p[i++] = 1./3 * last_y + 2./3 * y1; p[i++] = 2./3 * x1 + 1./3 * x; p[i++] = 2./3 * y1 + 1./3 * y; p[i++] = last_cubic_x = last_x = x; p[i++] = last_cubic_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %n", &x1, &y1, &x, &y, &n) == 4); /* shorthand/smooth quadratic Bezier curveto (T, t) (2 arguments) */ } else if (sscanf(s, " %1[Tt] %f %f %n", command, &x, &y, &n) == 3) { /*LOG(("shorthand/smooth quadratic Bezier curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_quad_x); y1 = last_y + (last_y - last_quad_y); last_quad_x = x1; last_quad_y = y1; if (*command == 't') { x1 += last_x; y1 += last_y; x += last_x; y += last_y; } p[i++] = 1./3 * last_x + 2./3 * x1; p[i++] = 1./3 * last_y + 2./3 * y1; p[i++] = 2./3 * x1 + 1./3 * x; p[i++] = 2./3 * y1 + 1./3 * y; p[i++] = last_cubic_x = last_x = x; p[i++] = last_cubic_y = last_y = y; s += n; } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2); /* elliptical arc (A, a) (7 arguments) */ } else if (sscanf(s, " %1[Aa] %f %f %f %f %f %f %f %n", command, &rx, &ry, &rotation, &large_arc, &sweep, &x, &y, &n) == 8) { do { p[i++] = svgtiny_PATH_LINE; if (*command == 'a') { x += last_x; y += last_y; } p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %f %f %f %n", &rx, &ry, &rotation, &large_arc, &sweep, &x, &y, &n) == 7); } else { fprintf(stderr, "parse failed at \"%s\"\n", s); break; } } free(path_d); if (i <= 4) { /* no real segments in path */ free(p); svgtiny_cleanup_state_local(&state); return svgtiny_OK; } err = svgtiny_add_path(p, i, &state); svgtiny_cleanup_state_local(&state); return err; }
svgtiny_code svgtiny_parse_svg(dom_element *svg, struct svgtiny_parse_state state) { float x, y, width, height; dom_string *view_box; dom_element *child; dom_exception exc; 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); exc = dom_element_get_attribute(svg, state.interned_viewBox, &view_box); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (view_box) { char *s = strndup(dom_string_data(view_box), dom_string_byte_length(view_box)); float min_x, min_y, vwidth, vheight; if (sscanf(s, "%f,%f,%f,%f", &min_x, &min_y, &vwidth, &vheight) == 4 || sscanf(s, "%f %f %f %f", &min_x, &min_y, &vwidth, &vheight) == 4) { state.ctm.a = (float) state.viewport_width / vwidth; state.ctm.d = (float) state.viewport_height / vheight; state.ctm.e += -min_x * state.ctm.a; state.ctm.f += -min_y * state.ctm.d; } free(s); dom_string_unref(view_box); } svgtiny_parse_transform_attributes(svg, &state); exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } while (child != NULL) { dom_element *next; dom_node_type nodetype; svgtiny_code code = svgtiny_OK; exc = dom_node_get_node_type(child, &nodetype); if (exc != DOM_NO_ERR) { dom_node_unref(child); return svgtiny_LIBDOM_ERROR; } if (nodetype == DOM_ELEMENT_NODE) { dom_string *nodename; exc = dom_node_get_node_name(child, &nodename); if (exc != DOM_NO_ERR) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (dom_string_caseless_isequal(state.interned_svg, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_g, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_a, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_path, nodename)) code = svgtiny_parse_path(child, state); else if (dom_string_caseless_isequal(state.interned_rect, nodename)) code = svgtiny_parse_rect(child, state); else if (dom_string_caseless_isequal(state.interned_circle, nodename)) code = svgtiny_parse_circle(child, state); else if (dom_string_caseless_isequal(state.interned_ellipse, nodename)) code = svgtiny_parse_ellipse(child, state); else if (dom_string_caseless_isequal(state.interned_line, nodename)) code = svgtiny_parse_line(child, state); else if (dom_string_caseless_isequal(state.interned_polyline, nodename)) code = svgtiny_parse_poly(child, state, false); else if (dom_string_caseless_isequal(state.interned_polygon, nodename)) code = svgtiny_parse_poly(child, state, true); else if (dom_string_caseless_isequal(state.interned_text, nodename)) code = svgtiny_parse_text(child, state); dom_string_unref(nodename); } if (code != svgtiny_OK) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return code; } exc = dom_node_get_next_sibling(child, (dom_node **) (void *) &next); dom_node_unref(child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } child = next; } svgtiny_cleanup_state_local(&state); return svgtiny_OK; }