From e1df0d095ac1d469cb19261faba99d542151e6f1 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sun, 25 Mar 2012 15:07:08 +0000 Subject: Initial attempt at imagemap libdomification svn path=/trunk/netsurf/; revision=13692 --- render/html.c | 48 +++++- render/html_internal.h | 20 +++ render/imagemap.c | 443 ++++++++++++++++++++++++++----------------------- render/imagemap.h | 2 +- 4 files changed, 301 insertions(+), 212 deletions(-) diff --git a/render/html.c b/render/html.c index f86595e1a..7dce3ebfa 100644 --- a/render/html.c +++ b/render/html.c @@ -96,7 +96,7 @@ static nsurl *html_user_stylesheet_url; static dom_string *html_dom_string_html; static dom_string *html_dom_string_head; static dom_string *html_dom_string_rel; -static dom_string *html_dom_string_href; +dom_string *html_dom_string_href; static dom_string *html_dom_string_hreflang; static dom_string *html_dom_string_type; static dom_string *html_dom_string_media; @@ -104,13 +104,27 @@ static dom_string *html_dom_string_sizes; static dom_string *html_dom_string_title; static dom_string *html_dom_string_base; static dom_string *html_dom_string_link; -static dom_string *html_dom_string_target; +dom_string *html_dom_string_target; static dom_string *html_dom_string__parent; static dom_string *html_dom_string__self; static dom_string *html_dom_string__blank; static dom_string *html_dom_string__top; static dom_string *html_dom_string_http_equiv; static dom_string *html_dom_string_content; +dom_string *html_dom_string_map; +dom_string *html_dom_string_id; +dom_string *html_dom_string_name; +dom_string *html_dom_string_area; +dom_string *html_dom_string_a; +dom_string *html_dom_string_nohref; +dom_string *html_dom_string_shape; +dom_string *html_dom_string_default; +dom_string *html_dom_string_rect; +dom_string *html_dom_string_rectangle; +dom_string *html_dom_string_coords; +dom_string *html_dom_string_circle; +dom_string *html_dom_string_poly; +dom_string *html_dom_string_polygon; static nserror html_create_html_data(html_content *c, const http_parameter *params) @@ -1185,7 +1199,7 @@ static void html_box_convert_done(html_content *c, bool success) } /* extract image maps - can't do this sensibly in xml_to_box */ - if (imagemap_extract(html, c) == false) { + if (imagemap_extract(c) == false) { LOG(("imagemap extraction failed")); html_destroy_objects(c); msg_data.error = messages_get("NoMemory"); @@ -3029,6 +3043,20 @@ static void html_fini(void) HTML_DOM_STRING_UNREF(_parent); HTML_DOM_STRING_UNREF(_top); HTML_DOM_STRING_UNREF(content); + HTML_DOM_STRING_UNREF(map); + HTML_DOM_STRING_UNREF(id); + HTML_DOM_STRING_UNREF(name); + HTML_DOM_STRING_UNREF(area); + HTML_DOM_STRING_UNREF(a); + HTML_DOM_STRING_UNREF(nohref); + HTML_DOM_STRING_UNREF(shape); + HTML_DOM_STRING_UNREF(default); + HTML_DOM_STRING_UNREF(rect); + HTML_DOM_STRING_UNREF(rectangle); + HTML_DOM_STRING_UNREF(coords); + HTML_DOM_STRING_UNREF(circle); + HTML_DOM_STRING_UNREF(poly); + HTML_DOM_STRING_UNREF(polygon); #undef HTML_DOM_STRING_UNREF @@ -3142,6 +3170,20 @@ nserror html_init(void) HTML_DOM_STRING_INTERN(_parent); HTML_DOM_STRING_INTERN(_top); HTML_DOM_STRING_INTERN(content); + HTML_DOM_STRING_INTERN(map); + HTML_DOM_STRING_INTERN(id); + HTML_DOM_STRING_INTERN(name); + HTML_DOM_STRING_INTERN(area); + HTML_DOM_STRING_INTERN(a); + HTML_DOM_STRING_INTERN(nohref); + HTML_DOM_STRING_INTERN(shape); + HTML_DOM_STRING_INTERN(default); + HTML_DOM_STRING_INTERN(rect); + HTML_DOM_STRING_INTERN(rectangle); + HTML_DOM_STRING_INTERN(coords); + HTML_DOM_STRING_INTERN(circle); + HTML_DOM_STRING_INTERN(poly); + HTML_DOM_STRING_INTERN(polygon); #undef HTML_DOM_STRING_INTERN diff --git a/render/html_internal.h b/render/html_internal.h index ff3270787..0bb47275b 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -132,6 +132,26 @@ void html_mouse_action(struct content *c, struct browser_window *bw, void html_overflow_scroll_callback(void *client_data, struct scrollbar_msg_data *scrollbar_data); +/* Useful dom_string pointers */ +struct dom_string; + +extern struct dom_string *html_dom_string_map; +extern struct dom_string *html_dom_string_id; +extern struct dom_string *html_dom_string_name; +extern struct dom_string *html_dom_string_area; +extern struct dom_string *html_dom_string_a; +extern struct dom_string *html_dom_string_nohref; +extern struct dom_string *html_dom_string_href; +extern struct dom_string *html_dom_string_target; +extern struct dom_string *html_dom_string_shape; +extern struct dom_string *html_dom_string_default; +extern struct dom_string *html_dom_string_rect; +extern struct dom_string *html_dom_string_rectangle; +extern struct dom_string *html_dom_string_coords; +extern struct dom_string *html_dom_string_circle; +extern struct dom_string *html_dom_string_poly; +extern struct dom_string *html_dom_string_polygon; + #endif diff --git a/render/imagemap.c b/render/imagemap.c index 5154d6161..7b612979e 100644 --- a/render/imagemap.c +++ b/render/imagemap.c @@ -75,13 +75,13 @@ struct imagemap { struct imagemap *next; /**< next entry in this hash chain */ }; -static bool imagemap_add(html_content *c, const char *key, +static bool imagemap_add(html_content *c, dom_string *key, struct mapentry *list); static bool imagemap_create(html_content *c); static bool imagemap_extract_map(dom_node *node, html_content *c, struct mapentry **entry); static bool imagemap_addtolist(dom_node *n, nsurl *base_url, - struct mapentry **entry); + struct mapentry **entry, dom_string *tagtype); static void imagemap_freelist(struct mapentry *list); static unsigned int imagemap_hash(const char *key); static int imagemap_point_in_poly(int num, float *xpt, float *ypt, @@ -96,7 +96,7 @@ static int imagemap_point_in_poly(int num, float *xpt, float *ypt, * \param list List of map regions * \return true on succes, false otherwise */ -bool imagemap_add(html_content *c, const char *key, struct mapentry *list) +bool imagemap_add(html_content *c, dom_string *key, struct mapentry *list) { struct imagemap *map; unsigned int slot; @@ -111,8 +111,9 @@ bool imagemap_add(html_content *c, const char *key, struct mapentry *list) map = calloc(1, sizeof(*map)); if (map == NULL) return false; - - map->key = strdup(key); + + /* \todo Stop relying on NULL termination of dom_string */ + map->key = strdup(dom_string_data(key)); if (map->key == NULL) { free(map); return false; @@ -120,7 +121,7 @@ bool imagemap_add(html_content *c, const char *key, struct mapentry *list) map->list = list; - slot = imagemap_hash(key); + slot = imagemap_hash(map->key); map->next = c->imagemaps[slot]; c->imagemaps[slot] = map; @@ -245,59 +246,87 @@ void imagemap_dump(html_content *c) /** * Extract all imagemaps from a document tree * - * \param node Root node of tree - * \param c The containing content + * \param c The content + * \param map_str A dom_string which is "map" * \return false on memory exhaustion, true otherwise */ -bool imagemap_extract(dom_node *node, html_content *c) +bool +imagemap_extract(html_content *c) { -#ifdef FIXME - dom_node *this_node; - struct mapentry *entry = NULL; - char *name; - - assert(node != NULL); - assert(c != NULL); - - if (node->type == XML_ELEMENT_NODE && - strcmp((const char *) node->name, "map") == 0) { - /* Ignore maps with no id or name */ - if ((name = (char *) xmlGetProp(node, - (const xmlChar *) "id")) == NULL && - (name = (char *) xmlGetProp(node, - (const xmlChar *) "name")) == NULL) { - return true; + dom_nodelist *nlist; + dom_exception exc; + unsigned long maybe_maps, mapnr; + + exc = dom_document_get_elements_by_tag_name(c->document, + html_dom_string_map, + &nlist); + if (exc != DOM_NO_ERR) { + return false; + } + + exc = dom_nodelist_get_length(nlist, &maybe_maps); + if (exc != DOM_NO_ERR) { + 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) { + goto out_nlist; } - - if (imagemap_extract_map(node, c, &entry) == false) { - xmlFree(name); - return false; + + exc = dom_element_get_attribute(node, html_dom_string_id, + &name); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + 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 ... block - */ - if (entry && imagemap_add(c, name, entry) == false) { - xmlFree(name); - return false; + + if (name == NULL) { + exc = dom_element_get_attribute(node, + html_dom_string_name, + &name); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + goto out_nlist; + } } - - xmlFree(name); - return true; - } else if (node->type != XML_ELEMENT_NODE) { - return true; - } - - /* now recurse */ - for (this_node = node->children; this_node != NULL; - this_node = this_node->next) { - if (imagemap_extract(this_node, c) == false) - return false; + + if (name != NULL) { + struct mapentry *entry = NULL; + if (imagemap_extract_map(node, c, &entry) == false) { + dom_string_unref(name); + dom_node_unref(node); + 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 ... block + */ + if ((entry != NULL) && + (imagemap_add(c, name, entry) == false)) { + dom_string_unref(name); + dom_node_unref(node); + goto out_nlist; + } + } + + dom_string_unref(name); + dom_node_unref(node); } -#endif + + dom_nodelist_unref(nlist); + return true; + +out_nlist: + + dom_nodelist_unref(nlist); + return false; } /** @@ -306,40 +335,67 @@ bool imagemap_extract(dom_node *node, html_content *c) * \param node XML node containing map * \param c Content containing document * \param entry List of map entries + * \param tname The sub-tags to consider on this pass * \return false on memory exhaustion, true otherwise */ -bool imagemap_extract_map(dom_node *node, html_content *c, - struct mapentry **entry) +static bool +imagemap_extract_map_entries(dom_node *node, html_content *c, + struct mapentry **entry, dom_string *tname) { -#ifdef FIXME - xmlNode *this_node; - - assert(c != NULL); - assert(entry != NULL); - - if (node->type == XML_ELEMENT_NODE) { - /** \todo ignore elements if there are other - * block-level elements present in map - */ - if (strcmp((const char *) node->name, "area") == 0 || - strcmp((const char *) node->name, "a") == 0) { - if (imagemap_addtolist(node, c->base_url, - entry) == false) - return false; - } - } else { - return true; + dom_nodelist *nlist; + dom_exception exc; + unsigned long tag_count, ent; + + exc = dom_element_get_elements_by_tag_name(node, tname, &nlist); + if (exc != DOM_NO_ERR) { + return false; } - - for (this_node = node->children; this_node != NULL; - this_node = this_node->next) { - if (imagemap_extract_map(this_node, c, entry) == false) + + exc = dom_nodelist_get_length(nlist, &tag_count); + if (exc != DOM_NO_ERR) { + dom_nodelist_unref(nlist); + return false; + } + + for (ent = 0; ent < tag_count; ++ent) { + dom_node *subnode; + + exc = dom_nodelist_item(nlist, ent, &subnode); + if (exc != DOM_NO_ERR) { + dom_nodelist_unref(nlist); + return false; + } + if (imagemap_addtolist(subnode, c->base_url, + entry, tname) == false) { + dom_node_unref(subnode); + dom_nodelist_unref(nlist); return false; + } + dom_node_unref(subnode); } -#endif + + dom_nodelist_unref(nlist); + return true; } +/** + * Extract an imagemap from html source + * + * \param node XML node containing map + * \param c Content containing document + * \param entry List of map entries + * \return false on memory exhaustion, true otherwise + */ +bool imagemap_extract_map(dom_node *node, html_content *c, + struct mapentry **entry) +{ + if (imagemap_extract_map_entries(node, c, entry, + html_dom_string_area) == false) + return false; + return imagemap_extract_map_entries(node, c, entry, + html_dom_string_a); +} /** * Adds an imagemap entry to the list * @@ -348,132 +404,97 @@ bool imagemap_extract_map(dom_node *node, html_content *c, * \param entry Pointer to list of entries * \return false on memory exhaustion, true otherwise */ -bool imagemap_addtolist(dom_node *n, nsurl *base_url, - struct mapentry **entry) +bool +imagemap_addtolist(dom_node *n, nsurl *base_url, + struct mapentry **entry, dom_string *tagtype) { -#ifdef FIXME - char *shape, *coords = NULL, *href, *target = NULL; + dom_exception exc; + dom_string *href = NULL, *target = NULL, *shape = NULL; + dom_string *coords = NULL; struct mapentry *new_map, *temp; - - assert(n != NULL); - assert(base_url != NULL); - assert(entry != NULL); - - if (strcmp((const char *) n->name, "area") == 0) { - xmlChar *nohref = xmlGetProp(n, (const xmlChar *) "nohref"); - - if (nohref != NULL) { - /* nohref attribute present - ignore this entry */ - xmlFree(nohref); - - return true; - } + bool ret = true; + + if (tagtype == html_dom_string_area) { + bool nohref = false; + exc = dom_element_has_attribute(n, + html_dom_string_nohref, + &nohref); + if ((exc != DOM_NO_ERR) || nohref) + /* Skip */ + goto ok_out; } - - /* no href -> ignore */ - if ((href = (char *) xmlGetProp(n, (const xmlChar *) "href")) == NULL) { - return true; + + exc = dom_element_get_attribute(n, html_dom_string_href, &href); + if (exc != DOM_NO_ERR) { + /* No href="" attribute, skip this element */ + goto ok_out; } - - target = (char *) xmlGetProp(n, (const xmlChar *) "target"); - - /* no shape -> shape is a rectangle */ - if ((shape = (char *) xmlGetProp(n, - (const xmlChar *) "shape")) == NULL) { - shape = (char *) xmlMemStrdup("rect"); + + exc = dom_element_get_attribute(n, html_dom_string_target, &target); + if (exc != DOM_NO_ERR) { + goto ok_out; } - - if (strcasecmp(shape, "default") != 0) { - /* no coords -> ignore */ - if ((coords = (char *) xmlGetProp(n, - (const xmlChar *) "coords")) == NULL) { - if (target) - xmlFree(target); - xmlFree(href); - xmlFree(shape); - return true; + + exc = dom_element_get_attribute(n, html_dom_string_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(html_dom_string_rect); + + if (!dom_string_caseless_isequal(shape, html_dom_string_default)) { + /* If not 'default' and there's no 'coords' give up */ + exc = dom_element_get_attribute(n, html_dom_string_coords, + &coords); + if (exc != DOM_NO_ERR) { + goto ok_out; } } - + new_map = calloc(1, sizeof(*new_map)); if (new_map == NULL) { - if (target) - xmlFree(target); - xmlFree(href); - xmlFree(shape); - if (coords) - xmlFree(coords); - return false; + goto bad_out; } - - /* extract area shape */ - if (strcasecmp(shape, "rect") == 0 || - strcasecmp(shape, "rectangle") == 0) { + + if (dom_string_caseless_isequal(shape, html_dom_string_rect) || + dom_string_caseless_isequal(shape, html_dom_string_rectangle)) new_map->type = IMAGEMAP_RECT; - } else if (strcasecmp(shape, "circle") == 0) { + else if (dom_string_caseless_isequal(shape, html_dom_string_circle)) new_map->type = IMAGEMAP_CIRCLE; - } else if (strcasecmp(shape, "poly") == 0 || - strcasecmp(shape, "polygon") == 0) { - /* polygon shape name is not valid but sites use it */ + else if (dom_string_caseless_isequal(shape, html_dom_string_poly) || + dom_string_caseless_isequal(shape, html_dom_string_polygon)) new_map->type = IMAGEMAP_POLY; - } else if (strcasecmp(shape, "default") == 0) { + else if (dom_string_caseless_isequal(shape, html_dom_string_default)) new_map->type = IMAGEMAP_DEFAULT; - } else { /* unknown shape -> bail */ - free(new_map); - if (target) - xmlFree(target); - xmlFree(href); - xmlFree(shape); - if (coords) - xmlFree(coords); - return true; - } - - if (box_extract_link(href, base_url, &new_map->url) == false) { - free(new_map); - if (target) - xmlFree(target); - xmlFree(href); - xmlFree(shape); - if (coords) - xmlFree(coords); - return false; - } - + else + goto bad_out; + + if (box_extract_link(dom_string_data(href), + base_url, &new_map->url) == false) + goto bad_out; + if (new_map->url == NULL) { - /* non-fatal error -> ignore this entry */ - free(new_map); - if (target) - xmlFree(target); - xmlFree(href); - xmlFree(shape); - if (coords) - xmlFree(coords); - return true; + /* non-fatal error -> ignore this */ + goto ok_free_map_out; } - - if (target) { - new_map->target = strdup(target); - if (new_map->target == NULL) { - nsurl_unref(new_map->url); - free(new_map); - xmlFree(target); - xmlFree(href); - xmlFree(shape); - if (coords) - xmlFree(coords); - return false; - } - - /* no longer needed */ - xmlFree(target); + + 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(coords, ","); + char *val = strtok((char *)dom_string_data(coords), ","); int num = 1; switch (new_map->type) { @@ -534,30 +555,13 @@ bool imagemap_addtolist(dom_node *n, nsurl *base_url, xcoords = realloc(new_map->bounds.poly.xcoords, num * sizeof(float)); if (xcoords == NULL) { - free(new_map->bounds.poly.ycoords); - free(new_map->bounds.poly.xcoords); - free(new_map->target); - nsurl_unref(new_map->url); - free(new_map); - xmlFree(href); - xmlFree(shape); - xmlFree(coords); - return false; + goto bad_out; } ycoords = realloc(new_map->bounds.poly.ycoords, num * sizeof(float)); if (ycoords == NULL) { - free(xcoords); - free(new_map->bounds.poly.ycoords); - free(new_map->bounds.poly.xcoords); - free(new_map->target); - nsurl_unref(new_map->url); - free(new_map); - xmlFree(href); - xmlFree(shape); - xmlFree(coords); - return false; + goto bad_out; } new_map->bounds.poly.xcoords = xcoords; @@ -577,7 +581,7 @@ bool imagemap_addtolist(dom_node *n, nsurl *base_url, break; } } - + new_map->next = NULL; if (entry && *entry) { @@ -589,13 +593,36 @@ bool imagemap_addtolist(dom_node *n, nsurl *base_url, else { (*entry) = new_map; } - - xmlFree(href); - xmlFree(shape); - if (coords) - xmlFree(coords); -#endif - return true; + + /* All good, linked in, let's clean up */ + goto ok_out; + +bad_out: + ret = false; +ok_free_map_out: + 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); + if (new_map != NULL) + 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; } /** diff --git a/render/imagemap.h b/render/imagemap.h index 56bee6b10..edbfea08f 100644 --- a/render/imagemap.h +++ b/render/imagemap.h @@ -28,7 +28,7 @@ struct hlcache_handle; void imagemap_destroy(struct html_content *c); void imagemap_dump(struct html_content *c); -bool imagemap_extract(dom_node *node, struct html_content *c); +bool imagemap_extract(struct html_content *c); nsurl *imagemap_get(struct html_content *c, const char *key, unsigned long x, unsigned long y, -- cgit v1.2.3