mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-22 18:32:16 +03:00
[project @ 2005-08-14 23:56:15 by jmb]
Move imagemap.[ch] into render/ Make imagemap URL extraction use box_extract_link svn path=/import/netsurf/; revision=1847
This commit is contained in:
parent
d3a5e7251d
commit
58d9b45e81
@ -29,12 +29,12 @@
|
||||
#endif
|
||||
#include "netsurf/desktop/browser.h"
|
||||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/desktop/imagemap.h"
|
||||
#include "netsurf/desktop/options.h"
|
||||
#include "netsurf/desktop/selection.h"
|
||||
#include "netsurf/desktop/textinput.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/form.h"
|
||||
#include "netsurf/render/imagemap.h"
|
||||
#include "netsurf/render/layout.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/messages.h"
|
||||
|
10
makefile
10
makefile
@ -19,16 +19,18 @@
|
||||
|
||||
OBJECTS_COMMON = content.o fetch.o fetchcache.o url_store.o # content/
|
||||
OBJECTS_COMMON += css.o css_enum.o parser.o ruleset.o scanner.o # css/
|
||||
OBJECTS_COMMON += box.o box_construct.o box_normalise.o form.o html.o \
|
||||
html_redraw.o layout.o list.o table.o textplain.o # render/
|
||||
OBJECTS_COMMON += box.o box_construct.o box_normalise.o form.o \
|
||||
html.o html_redraw.o imagemap.o layout.o list.o \
|
||||
table.o textplain.o # render/
|
||||
OBJECTS_COMMON += messages.o talloc.o url.o utf8.o \
|
||||
utils.o # utils/
|
||||
OBJECTS_COMMON += imagemap.o loginlist.o options.o tree.o # desktop/
|
||||
OBJECTS_COMMON += loginlist.o options.o tree.o # desktop/
|
||||
|
||||
OBJECTS_IMAGE = gif.o gifread.o jpeg.o mng.o # image/
|
||||
|
||||
OBJECTS_RISCOS = $(OBJECTS_COMMON) $(OBJECTS_IMAGE)
|
||||
OBJECTS_RISCOS += browser.o netsurf.o selection.o textinput.o version.o # desktop/
|
||||
OBJECTS_RISCOS += browser.o netsurf.o selection.o textinput.o \
|
||||
version.o # desktop/
|
||||
OBJECTS_RISCOS += 401login.o bitmap.o buffer.o debugwin.o \
|
||||
dialog.o download.o draw.o filename.o filetype.o font.o \
|
||||
global_history.o gui.o help.o history.o hotlist.o image.o \
|
||||
|
@ -254,6 +254,7 @@ struct box *box_at_point(struct box *box, int x, int y,
|
||||
struct box *box_object_at_point(struct content *c, int x, int y);
|
||||
struct box *box_find_by_id(struct box *box, const char *id);
|
||||
void box_dump(struct box *box, unsigned int depth);
|
||||
bool box_extract_link(const char *rel, const char *base, char **result);
|
||||
|
||||
bool box_vscrollbar_present(const struct box *box);
|
||||
bool box_hscrollbar_present(const struct box *box);
|
||||
|
@ -109,7 +109,6 @@ static bool box_embed(BOX_SPECIAL_PARAMS);
|
||||
static bool box_iframe(BOX_SPECIAL_PARAMS);
|
||||
static bool box_get_attribute(xmlNode *n, const char *attribute,
|
||||
void *context, char **value);
|
||||
static bool box_extract_link(const char *rel, const char *base, char **result);
|
||||
static struct box_multi_length *box_parse_multi_lengths(const char *s,
|
||||
unsigned int *count, void *context);
|
||||
|
||||
|
@ -19,12 +19,12 @@
|
||||
#include "netsurf/content/content.h"
|
||||
#include "netsurf/content/fetch.h"
|
||||
#include "netsurf/content/fetchcache.h"
|
||||
#include "netsurf/desktop/imagemap.h"
|
||||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/desktop/options.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/html.h"
|
||||
#include "netsurf/render/imagemap.h"
|
||||
#include "netsurf/render/layout.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/messages.h"
|
||||
|
676
render/imagemap.c
Normal file
676
render/imagemap.c
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
|
||||
*
|
||||
* Much of this shamelessly copied from utils/messages.c
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "netsurf/content/content.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/imagemap.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
|
||||
#define HASH_SIZE 31 /* fixed size hash table */
|
||||
|
||||
typedef enum {
|
||||
IMAGEMAP_DEFAULT,
|
||||
IMAGEMAP_RECT,
|
||||
IMAGEMAP_CIRCLE,
|
||||
IMAGEMAP_POLY
|
||||
} imagemap_entry_type;
|
||||
|
||||
struct mapentry {
|
||||
imagemap_entry_type type; /**< type of shape */
|
||||
char *url; /**< absolute url to go to */
|
||||
union {
|
||||
struct {
|
||||
int x; /**< x coordinate of centre */
|
||||
int y; /**< y coordinate of center */
|
||||
int r; /**< radius of circle */
|
||||
} circle;
|
||||
struct {
|
||||
int x0; /**< left hand edge */
|
||||
int y0; /**< top edge */
|
||||
int x1; /**< right hand edge */
|
||||
int y1; /**< bottom edge */
|
||||
} rect;
|
||||
struct {
|
||||
int num; /**< number of points */
|
||||
float *xcoords; /**< x coordinates */
|
||||
float *ycoords; /**< y coordinates */
|
||||
} poly;
|
||||
} bounds;
|
||||
struct mapentry *next; /**< next entry in list */
|
||||
};
|
||||
|
||||
struct imagemap {
|
||||
char *key; /**< key for this entry */
|
||||
struct mapentry *list; /**< pointer to linked list of entries */
|
||||
struct imagemap *next; /**< next entry in this hash chain */
|
||||
};
|
||||
|
||||
static bool imagemap_add(struct content *c, const char *key,
|
||||
struct mapentry *list);
|
||||
static bool imagemap_create(struct content *c);
|
||||
static bool imagemap_extract_map(xmlNode *node, struct content *c,
|
||||
struct mapentry **entry);
|
||||
static bool imagemap_addtolist(xmlNode *n, char *base_url,
|
||||
struct mapentry **entry);
|
||||
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,
|
||||
unsigned long x, unsigned long y, unsigned long click_x,
|
||||
unsigned long click_y);
|
||||
|
||||
/**
|
||||
* Add an imagemap to the hashtable, creating it if it doesn't exist
|
||||
*
|
||||
* @param c The containing content
|
||||
* @param key The name of the imagemap
|
||||
* @param list List of map regions
|
||||
* \return true on succes, false otherwise
|
||||
*/
|
||||
bool imagemap_add(struct content *c, const char *key, struct mapentry *list)
|
||||
{
|
||||
struct imagemap *map;
|
||||
unsigned int slot;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(c->type == CONTENT_HTML);
|
||||
assert(key != NULL);
|
||||
assert(list != NULL);
|
||||
|
||||
imagemap_create(c);
|
||||
|
||||
map = calloc(1, sizeof(*map));
|
||||
if (!map) {
|
||||
return false;
|
||||
}
|
||||
map->key = strdup(key);
|
||||
if (!map->key) {
|
||||
free(map);
|
||||
return false;
|
||||
}
|
||||
map->list = list;
|
||||
slot = imagemap_hash(key);
|
||||
map->next = c->data.html.imagemaps[slot];
|
||||
c->data.html.imagemaps[slot] = map;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create hashtable of imagemaps
|
||||
*
|
||||
* @param c The containing content
|
||||
* \return true on success, false otherwise
|
||||
*/
|
||||
bool imagemap_create(struct content *c)
|
||||
{
|
||||
assert(c != NULL);
|
||||
assert(c->type == CONTENT_HTML);
|
||||
|
||||
if (c->data.html.imagemaps == 0) {
|
||||
c->data.html.imagemaps = calloc(HASH_SIZE,
|
||||
sizeof(struct imagemap));
|
||||
if (!c->data.html.imagemaps) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy hashtable of imagemaps
|
||||
*
|
||||
* @param c The containing content
|
||||
*/
|
||||
void imagemap_destroy(struct content *c)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(c->type == CONTENT_HTML);
|
||||
|
||||
/* no imagemaps -> return */
|
||||
if (c->data.html.imagemaps == 0) return;
|
||||
|
||||
for (i = 0; i != HASH_SIZE; i++) {
|
||||
struct imagemap *map, *next;
|
||||
map = c->data.html.imagemaps[i];
|
||||
while (map != 0) {
|
||||
next = map->next;
|
||||
imagemap_freelist(map->list);
|
||||
free(map->key);
|
||||
free(map);
|
||||
map = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(c->data.html.imagemaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump imagemap data to the log
|
||||
*
|
||||
* @param c The containing content
|
||||
*/
|
||||
void imagemap_dump(struct content *c)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
int j;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(c->type == CONTENT_HTML);
|
||||
|
||||
if (c->data.html.imagemaps == 0) return;
|
||||
|
||||
for (i = 0; i != HASH_SIZE; i++) {
|
||||
struct imagemap *map;
|
||||
struct mapentry *entry;
|
||||
map = c->data.html.imagemaps[i];
|
||||
while (map != 0) {
|
||||
LOG(("Imagemap: %s", map->key));
|
||||
for (entry = map->list; entry; entry = entry->next) {
|
||||
switch (entry->type) {
|
||||
case IMAGEMAP_DEFAULT:
|
||||
LOG(("\tDefault: %s", entry->url));
|
||||
break;
|
||||
case IMAGEMAP_RECT:
|
||||
LOG(("\tRectangle: %s: [(%d,%d),(%d,%d)]",
|
||||
entry->url,
|
||||
entry->bounds.rect.x0,
|
||||
entry->bounds.rect.y0,
|
||||
entry->bounds.rect.x1,
|
||||
entry->bounds.rect.y1));
|
||||
break;
|
||||
case IMAGEMAP_CIRCLE:
|
||||
LOG(("\tCircle: %s: [(%d,%d),%d]",
|
||||
entry->url,
|
||||
entry->bounds.circle.x,
|
||||
entry->bounds.circle.y,
|
||||
entry->bounds.circle.r));
|
||||
break;
|
||||
case IMAGEMAP_POLY:
|
||||
LOG(("\tPolygon: %s:", entry->url));
|
||||
for (j=0; j!=entry->bounds.poly.num;
|
||||
j++) {
|
||||
fprintf(stderr, "(%d,%d) ",
|
||||
(int)entry->bounds.poly.xcoords[j],
|
||||
(int)entry->bounds.poly.ycoords[j]);
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
map = map->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all imagemaps from a document tree
|
||||
*
|
||||
* @param node Root node of tree
|
||||
* @param c The containing content
|
||||
* \return false on memory exhaustion, true otherwise
|
||||
*/
|
||||
bool imagemap_extract(xmlNode *node, struct content *c)
|
||||
{
|
||||
xmlNode *this_node;
|
||||
struct mapentry *entry = 0;
|
||||
char *name;
|
||||
|
||||
assert(node != NULL);
|
||||
assert(c != NULL);
|
||||
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
if (strcmp(node->name, "map") == 0) {
|
||||
if ((name = (char*)xmlGetProp(node, (const xmlChar*)"name")) == NULL)
|
||||
return true;
|
||||
if (!imagemap_extract_map(node, c, &entry)) {
|
||||
xmlFree(name);
|
||||
return false;
|
||||
}
|
||||
/* 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) {
|
||||
if (!imagemap_add(c, name, entry)) {
|
||||
xmlFree(name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
xmlFree(name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else return true;
|
||||
|
||||
/* now recurse */
|
||||
for (this_node = node->children; this_node != 0;
|
||||
this_node = this_node->next) {
|
||||
if (!imagemap_extract(this_node, c))
|
||||
return false;
|
||||
}
|
||||
|
||||
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(xmlNode *node, struct content *c,
|
||||
struct mapentry **entry)
|
||||
{
|
||||
xmlNode *this_node;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(entry != NULL);
|
||||
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
/** \todo ignore <area> elements if there are other
|
||||
* block-level elements present in map
|
||||
*/
|
||||
if (strcmp(node->name, "area") == 0 ||
|
||||
strcmp(node->name, "a") == 0) {
|
||||
return imagemap_addtolist(node,
|
||||
c->data.html.base_url, entry);
|
||||
}
|
||||
}
|
||||
else return true;
|
||||
|
||||
for (this_node = node->children; this_node != 0;
|
||||
this_node = this_node->next) {
|
||||
if (!imagemap_extract_map(this_node, c, entry))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an imagemap entry to the list
|
||||
*
|
||||
* \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
|
||||
* \return false on memory exhaustion, true otherwise
|
||||
*/
|
||||
bool imagemap_addtolist(xmlNode *n, char *base_url, struct mapentry **entry)
|
||||
{
|
||||
char *shape, *coords = 0, *href, *val;
|
||||
int num;
|
||||
struct mapentry *new_map, *temp;
|
||||
|
||||
assert(n != NULL);
|
||||
assert(base_url != NULL);
|
||||
assert(entry != NULL);
|
||||
|
||||
if (strcmp(n->name, "area") == 0) {
|
||||
/* nohref attribute present - ignore this entry */
|
||||
if (xmlGetProp(n, (const xmlChar*)"nohref") != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* no href -> ignore */
|
||||
if ((href = (char*)xmlGetProp(n, (const xmlChar*)"href")) == NULL) {
|
||||
return true;
|
||||
}
|
||||
/* no shape -> shape is a rectangle */
|
||||
if ((shape = (char*)xmlGetProp(n, (const xmlChar*)"shape")) == NULL) {
|
||||
shape = (char*)xmlMemStrdup("rect");
|
||||
}
|
||||
if (strcasecmp(shape, "default") != 0) {
|
||||
/* no coords -> ignore */
|
||||
if ((coords = (char*)xmlGetProp(n, (const xmlChar*)"coords")) == NULL) {
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new_map = calloc(1, sizeof(*new_map));
|
||||
if (!new_map) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* extract area shape */
|
||||
if (strcasecmp(shape, "rect") == 0) {
|
||||
new_map->type = IMAGEMAP_RECT;
|
||||
}
|
||||
else if (strcasecmp(shape, "circle") == 0) {
|
||||
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 */
|
||||
new_map->type = IMAGEMAP_POLY;
|
||||
}
|
||||
else if (strcasecmp(shape, "default") == 0) {
|
||||
new_map->type = IMAGEMAP_DEFAULT;
|
||||
}
|
||||
else { /* unknown shape -> bail */
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!box_extract_link(href, base_url, &new_map->url)) {
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!new_map->url) {
|
||||
/* non-fatal error -> ignore this entry */
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (new_map->type != IMAGEMAP_DEFAULT) {
|
||||
/* coordinates are a comma-separated list of values */
|
||||
val = strtok(coords, ",");
|
||||
num = 1;
|
||||
|
||||
switch (new_map->type) {
|
||||
case IMAGEMAP_RECT:
|
||||
/* (left, top, right, bottom) */
|
||||
while (val && 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('\0', ",");
|
||||
}
|
||||
break;
|
||||
case IMAGEMAP_CIRCLE:
|
||||
/* (x, y, radius ) */
|
||||
while (val && 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('\0', ",");
|
||||
}
|
||||
break;
|
||||
case IMAGEMAP_POLY:
|
||||
new_map->bounds.poly.xcoords =
|
||||
calloc(0, sizeof(*new_map->bounds.poly.xcoords));
|
||||
if (!new_map->bounds.poly.xcoords) {
|
||||
free(new_map->url);
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return false;
|
||||
}
|
||||
new_map->bounds.poly.ycoords =
|
||||
calloc(0, sizeof(*new_map->bounds.poly.ycoords));
|
||||
if (!new_map->bounds.poly.ycoords) {
|
||||
free(new_map->bounds.poly.xcoords);
|
||||
free(new_map->url);
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return false;
|
||||
}
|
||||
int x, y;
|
||||
float *xcoords, *ycoords;
|
||||
while (val) {
|
||||
x = atoi(val);
|
||||
val = strtok('\0', ",");
|
||||
if (!val)
|
||||
break;
|
||||
y = atoi(val);
|
||||
|
||||
xcoords = realloc(new_map->bounds.poly.xcoords,
|
||||
num * sizeof(*new_map->bounds.poly.xcoords));
|
||||
if (!xcoords) {
|
||||
free(new_map->bounds.poly.ycoords);
|
||||
free(new_map->bounds.poly.xcoords);
|
||||
free(new_map->url);
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return false;
|
||||
}
|
||||
ycoords = realloc(new_map->bounds.poly.ycoords,
|
||||
num * sizeof(*new_map->bounds.poly.ycoords));
|
||||
if (!ycoords) {
|
||||
free(new_map->bounds.poly.ycoords);
|
||||
free(new_map->bounds.poly.xcoords);
|
||||
free(new_map->url);
|
||||
free(new_map);
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
return false;
|
||||
}
|
||||
|
||||
new_map->bounds.poly.xcoords = xcoords;
|
||||
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('\0', ",");
|
||||
}
|
||||
|
||||
new_map->bounds.poly.num = num-1;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new_map->next = 0;
|
||||
if (entry && (*entry)) {
|
||||
/* add to END of list */
|
||||
for (temp = (*entry); temp->next != 0; temp = temp->next)
|
||||
;
|
||||
temp->next = new_map;
|
||||
}
|
||||
else {
|
||||
(*entry) = new_map;
|
||||
}
|
||||
|
||||
xmlFree(href);
|
||||
xmlFree(shape);
|
||||
xmlFree(coords);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free list of imagemap entries
|
||||
*
|
||||
* @param list Pointer to head of list
|
||||
*/
|
||||
void imagemap_freelist(struct mapentry *list)
|
||||
{
|
||||
struct mapentry *entry, *prev;
|
||||
|
||||
assert(list != NULL);
|
||||
|
||||
entry = list;
|
||||
|
||||
while (entry != 0) {
|
||||
prev = entry;
|
||||
free(entry->url);
|
||||
if (entry->type == IMAGEMAP_POLY) {
|
||||
free(entry->bounds.poly.xcoords);
|
||||
free(entry->bounds.poly.ycoords);
|
||||
}
|
||||
entry = entry->next;
|
||||
free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve url associated with imagemap entry
|
||||
*
|
||||
* @param c The containing content
|
||||
* @param key The map name to search for
|
||||
* @param x The left edge of the containing box
|
||||
* @param y The top edge of the containing box
|
||||
* @param click_x The horizontal location of the click
|
||||
* @param click_y The vertical location of the click
|
||||
* @return The url associated with this area, or NULL if not found
|
||||
*/
|
||||
char *imagemap_get(struct content *c, const char *key, unsigned long x,
|
||||
unsigned long y, unsigned long click_x,
|
||||
unsigned long click_y)
|
||||
{
|
||||
unsigned int slot = 0;
|
||||
struct imagemap *map;
|
||||
struct mapentry *entry;
|
||||
unsigned long cx, cy;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(c->type == CONTENT_HTML);
|
||||
if (key == NULL) return NULL;
|
||||
if (c->data.html.imagemaps == NULL) return NULL;
|
||||
|
||||
slot = imagemap_hash(key);
|
||||
|
||||
for (map = c->data.html.imagemaps[slot]; map != 0; map = map->next) {
|
||||
if (map->key != 0 && strcasecmp(map->key, key) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (map == 0 || map->list == NULL) return NULL;
|
||||
|
||||
for (entry = map->list; entry; entry = entry->next) {
|
||||
switch (entry->type) {
|
||||
case IMAGEMAP_DEFAULT:
|
||||
/* just return the URL. no checks required */
|
||||
return entry->url;
|
||||
break;
|
||||
case IMAGEMAP_RECT:
|
||||
if (click_x >= x + entry->bounds.rect.x0 &&
|
||||
click_x <= x + entry->bounds.rect.x1 &&
|
||||
click_y >= y + entry->bounds.rect.y0 &&
|
||||
click_y <= y + entry->bounds.rect.y1) {
|
||||
return entry->url;
|
||||
}
|
||||
break;
|
||||
case IMAGEMAP_CIRCLE:
|
||||
cx = x + entry->bounds.circle.x - click_x;
|
||||
cy = y + entry->bounds.circle.y - click_y;
|
||||
if ((cx * cx + cy * cy) <=
|
||||
(unsigned long)(entry->bounds.circle.r *
|
||||
entry->bounds.circle.r)) {
|
||||
return entry->url;
|
||||
}
|
||||
break;
|
||||
case IMAGEMAP_POLY:
|
||||
if (imagemap_point_in_poly(entry->bounds.poly.num,
|
||||
entry->bounds.poly.xcoords,
|
||||
entry->bounds.poly.ycoords, x, y,
|
||||
click_x, click_y)) {
|
||||
return entry->url;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash function
|
||||
*
|
||||
* @param key The key to hash
|
||||
* @return The hashed value
|
||||
*/
|
||||
unsigned int imagemap_hash(const char *key)
|
||||
{
|
||||
unsigned int z = 0;
|
||||
|
||||
if (key == 0) return 0;
|
||||
|
||||
for (; *key != 0; key++) {
|
||||
z += *key & 0x1f;
|
||||
}
|
||||
|
||||
return (z % (HASH_SIZE - 1)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a point lies within an arbitrary polygon
|
||||
* Modified from comp.graphics.algorithms FAQ 2.03
|
||||
*
|
||||
* @param num Number of vertices
|
||||
* @param xpt Array of x coordinates
|
||||
* @param ypt Array of y coordinates
|
||||
* @param x Left hand edge of containing box
|
||||
* @param y Top edge of containing box
|
||||
* @param click_x X coordinate of click
|
||||
* @param click_y Y coordinate of click
|
||||
* @return 1 if point is in polygon, 0 if outside. 0 or 1 if on boundary
|
||||
*/
|
||||
int imagemap_point_in_poly(int num, float *xpt, float *ypt, unsigned long x,
|
||||
unsigned long y, unsigned long click_x,
|
||||
unsigned long click_y)
|
||||
{
|
||||
int i, j, c=0;
|
||||
|
||||
assert(xpt != NULL);
|
||||
assert(ypt != NULL);
|
||||
|
||||
for (i = 0, j = num-1; i < num; j = i++) {
|
||||
if ((((ypt[i]+y <= click_y) && (click_y < ypt[j]+y)) ||
|
||||
((ypt[j]+y <= click_y) && (click_y < ypt[i]+y))) &&
|
||||
(click_x < (xpt[j] - xpt[i]) *
|
||||
(click_y - (ypt[i]+y)) / (ypt[j] - ypt[i]) + xpt[i]+x))
|
||||
c = !c;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
21
render/imagemap.h
Normal file
21
render/imagemap.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
|
||||
*/
|
||||
|
||||
#ifndef _NETSURF_RENDER_IMAGEMAP_H_
|
||||
#define _NETSURF_RENDER_IMAGEMAP_H_
|
||||
|
||||
#include "libxml/HTMLtree.h"
|
||||
|
||||
struct content;
|
||||
|
||||
void imagemap_destroy(struct content *c);
|
||||
void imagemap_dump(struct content *c);
|
||||
bool imagemap_extract(xmlNode *node, struct content *c);
|
||||
char *imagemap_get(struct content *c, const char *key, unsigned long x,
|
||||
unsigned long y, unsigned long click_x, unsigned long click_y);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user