summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/content.c99
-rw-r--r--content/content.h20
-rw-r--r--content/content_protected.h7
-rw-r--r--desktop/browser.c177
-rw-r--r--desktop/browser.h4
-rw-r--r--image/image_cache.c11
-rw-r--r--image/image_cache.h2
-rw-r--r--render/html.c101
8 files changed, 321 insertions, 100 deletions
diff --git a/content/content.c b/content/content.c
index 7b722a274..28d18bcab 100644
--- a/content/content.c
+++ b/content/content.c
@@ -376,6 +376,8 @@ void content__reformat(struct content *c, bool background,
void content_destroy(struct content *c)
{
+ struct content_rfc5988_link *link;
+
assert(c);
LOG(("content %p %s", c,
nsurl_access(llcache_handle_get_url(c->llcache))));
@@ -389,6 +391,12 @@ void content_destroy(struct content *c)
lwc_string_unref(c->mime_type);
+ /* release metadata links */
+ link = c->links;
+ while (link != NULL) {
+ link = content__free_rfc5988_link(link);
+ }
+
talloc_free(c);
}
@@ -744,6 +752,97 @@ bool content__set_title(struct content *c, const char *title)
return true;
}
+struct content_rfc5988_link *
+content_find_rfc5988_link(hlcache_handle *h, lwc_string *rel)
+{
+ struct content *c = hlcache_handle_get_content(h);
+ struct content_rfc5988_link *link = c->links;
+ bool rel_match = false;
+
+ while (link != NULL) {
+ lwc_string_caseless_isequal(link->rel, rel, &rel_match);
+ if (rel_match) {
+ break;
+ }
+ link = link->next;
+ }
+ return link;
+}
+
+struct content_rfc5988_link *
+content__free_rfc5988_link(struct content_rfc5988_link *link)
+{
+ struct content_rfc5988_link *next;
+
+ next = link->next;
+
+ lwc_string_unref(link->rel);
+ nsurl_unref(link->href);
+ if (link->hreflang != NULL) {
+ lwc_string_unref(link->hreflang);
+ }
+ if (link->type != NULL) {
+ lwc_string_unref(link->type);
+ }
+ if (link->media != NULL) {
+ lwc_string_unref(link->media);
+ }
+ if (link->sizes != NULL) {
+ lwc_string_unref(link->sizes);
+ }
+ free(link);
+
+ return next;
+}
+
+bool content__add_rfc5988_link(struct content *c,
+ const struct content_rfc5988_link *link)
+{
+ struct content_rfc5988_link *newlink;
+ union content_msg_data msg_data;
+
+ /* a link relation must be present for it to be a link */
+ if (link->rel == NULL) {
+ return false;
+ }
+
+ /* a link href must be present for it to be a link */
+ if (link->href == NULL) {
+ return false;
+ }
+
+ newlink = calloc(1, sizeof(struct content_rfc5988_link));
+ if (newlink == NULL) {
+ return false;
+ }
+
+ /* copy values */
+ newlink->rel = lwc_string_ref(link->rel);
+ newlink->href = nsurl_ref(link->href);
+ if (link->hreflang != NULL) {
+ newlink->hreflang = lwc_string_ref(link->hreflang);
+ }
+ if (link->type != NULL) {
+ newlink->type = lwc_string_ref(link->type);
+ }
+ if (link->media != NULL) {
+ newlink->media = lwc_string_ref(link->media);
+ }
+ if (link->sizes != NULL) {
+ newlink->sizes = lwc_string_ref(link->sizes);
+ }
+
+ /* add to metadata link to list */
+ newlink->next = c->links;
+ c->links = newlink;
+
+ /* broadcast the data */
+ msg_data.rfc5988_link = newlink;
+ content_broadcast(c, CONTENT_MSG_LINK, msg_data);
+
+ return true;
+}
+
/**
* Retrieve computed type of content
*
diff --git a/content/content.h b/content/content.h
index eb8fbe689..3fd0bd63a 100644
--- a/content/content.h
+++ b/content/content.h
@@ -75,6 +75,18 @@ typedef enum {
CONTENT_MSG_LINK, /**< RFC5988 link */
} content_msg;
+/** RFC5988 metadata link */
+struct content_rfc5988_link {
+ struct content_rfc5988_link *next; /**< next rfc5988_link in list */
+
+ lwc_string *rel; /**< the link relationship - must be present */
+ nsurl *href; /* the link href - must be present */
+ lwc_string *hreflang;
+ lwc_string *type;
+ lwc_string *media;
+ lwc_string *sizes;
+};
+
/** Extra data for some content_msg messages. */
union content_msg_data {
const char *error; /**< Error message, for CONTENT_MSG_ERROR. */
@@ -97,11 +109,7 @@ union content_msg_data {
/** Low-level cache handle, for CONTENT_MSG_DOWNLOAD */
struct llcache_handle *download;
/** rfc5988 link data CONTENT_MSG_RFC5988_LINK */
- struct {
- nsurl *url;
- char *rel;
- char *type;
- } rfc5988_link;
+ struct content_rfc5988_link *rfc5988_link;
};
@@ -167,6 +175,8 @@ void content_close(struct hlcache_handle *h);
struct selection *content_get_selection(struct hlcache_handle *h);
void content_get_contextual_content(struct hlcache_handle *h,
int x, int y, struct contextual_content *data);
+struct content_rfc5988_link *content_find_rfc5988_link(struct hlcache_handle *c,
+ lwc_string *rel);
/* Member accessors */
content_type content_get_type(struct hlcache_handle *c);
diff --git a/content/content_protected.h b/content/content_protected.h
index eeaa67cbf..05b1940f2 100644
--- a/content/content_protected.h
+++ b/content/content_protected.h
@@ -108,6 +108,8 @@ struct content {
nsurl *refresh; /**< URL for refresh request */
+ struct content_rfc5988_link *links; /**< list of metadata links */
+
unsigned int time; /**< Creation time,
if LOADING or READY,
otherwise total time. */
@@ -160,6 +162,11 @@ void content_broadcast(struct content *c, content_msg msg,
void content_add_error(struct content *c, const char *token,
unsigned int line);
+bool content__add_rfc5988_link(struct content *c,
+ const struct content_rfc5988_link *link);
+struct content_rfc5988_link *content__free_rfc5988_link(
+ struct content_rfc5988_link *link);
+
void content__reformat(struct content *c, bool background,
int width, int height);
void content__request_redraw(struct content *c,
diff --git a/desktop/browser.c b/desktop/browser.c
index ed1cfc345..db9c9249f 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -877,6 +877,8 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
nsurl_unref(nsref);
}
+
+
/**
* Callback for fetchcache() for browser window favicon fetches.
*/
@@ -889,16 +891,47 @@ static nserror browser_window_favicon_callback(hlcache_handle *c,
switch (event->type) {
case CONTENT_MSG_DONE:
LOG(("favicon contents for %p done!", bw));
- /* content_get_bitmap on the bw->favicon should give
- us the favicon at this point
- */
+
+ if (bw->current_favicon != NULL) {
+ content_status status =
+ content_get_status(bw->current_favicon);
+
+ if ((status == CONTENT_STATUS_READY) ||
+ (status == CONTENT_STATUS_DONE))
+ content_close(bw->current_favicon);
+
+ hlcache_handle_release(bw->current_favicon);
+ }
+
+ bw->current_favicon = c;
+ bw->loading_favicon = NULL;
+
+ /* content_get_bitmap on the hlcache_handle should give
+ * us the favicon bitmap at this point
+ */
if (bw->window != NULL) {
- gui_window_set_icon(bw->window, bw->favicon);
+ gui_window_set_icon(bw->window, c);
} else {
LOG(("null browser window on favicon!"));
}
break;
+ case CONTENT_MSG_ERROR:
+
+ /* clean up after ourselves */
+ if (c == bw->loading_favicon)
+ bw->loading_favicon = NULL;
+ else if (c == bw->current_favicon) {
+ bw->current_favicon = NULL;
+ }
+
+ hlcache_handle_release(c);
+
+ /** @todo if this was not the default
+ * resource:favicon.png start a fetch for it.
+ */
+ break;
+
default:
LOG(("favicon unhandled event"));
break;
@@ -906,6 +939,57 @@ static nserror browser_window_favicon_callback(hlcache_handle *c,
return NSERROR_OK;
}
+static void browser_window_update_favicon(hlcache_handle *c,
+ struct browser_window *bw)
+{
+ lwc_string *icon_str;
+ struct content_rfc5988_link *link;
+ nsurl *nsref = NULL;
+ nsurl *nsurl;
+ nserror error;
+
+ /* already fetching the favicon - use that */
+ if (bw->loading_favicon != NULL)
+ return;
+
+ /* look for favicon metadata link */
+ lwc_intern_string("icon", SLEN("icon"), &icon_str);
+ link = content_find_rfc5988_link(c, icon_str);
+ lwc_string_unref(icon_str);
+
+ if (link == NULL) {
+ lwc_intern_string("shortcut icon", SLEN("shortcut_icon"),
+ &icon_str);
+ link = content_find_rfc5988_link(c, icon_str);
+ lwc_string_unref(icon_str);
+ }
+
+ if (link == NULL) {
+ /* no favicon via link, try for the default location - bletch */
+ error = nsurl_join(content_get_url(c), "/favicon.ico", &nsurl);
+ if (error != NSERROR_OK) {
+ LOG(("Unable to create default location url"));
+ return;
+ }
+ } else {
+ nsurl = link->href;
+ nsurl_ref(nsurl);
+ }
+
+ hlcache_handle_retrieve(nsurl,
+ HLCACHE_RETRIEVE_MAY_DOWNLOAD |
+ HLCACHE_RETRIEVE_SNIFF_TYPE,
+ nsref,
+ NULL,
+ browser_window_favicon_callback,
+ bw,
+ NULL,
+ CONTENT_IMAGE,
+ &bw->loading_favicon);
+
+ nsurl_unref(nsurl);
+}
+
/**
* Callback for fetchcache() for browser window fetches.
*/
@@ -962,18 +1046,6 @@ nserror browser_window_callback(hlcache_handle *c,
hlcache_handle_release(bw->current_content);
}
- if (bw->favicon != NULL) {
- content_status status =
- content_get_status(bw->favicon);
-
- if (status == CONTENT_STATUS_READY ||
- status == CONTENT_STATUS_DONE)
- content_close(bw->favicon);
-
- hlcache_handle_release(bw->favicon);
- bw->favicon = NULL;
- }
-
bw->current_content = c;
bw->loading_content = NULL;
@@ -1040,32 +1112,7 @@ nserror browser_window_callback(hlcache_handle *c,
browser_window_update(bw, false);
browser_window_set_status(bw, content_get_status_message(c));
browser_window_stop_throbber(bw);
- if (bw->favicon == NULL) {
- /* no favicon via link - try for the default location - bletch */
- nsurl *nsref = NULL;
- nsurl *nsurl;
- nserror error;
-
- error = nsurl_join(content_get_url(c), "/favicon.ico", &nsurl);
- if (error == NSERROR_OK) {
-
-
- hlcache_handle_retrieve(nsurl,
- HLCACHE_RETRIEVE_MAY_DOWNLOAD |
- HLCACHE_RETRIEVE_SNIFF_TYPE,
- nsref,
- NULL,
- browser_window_favicon_callback,
- bw,
- NULL,
- CONTENT_IMAGE,
- &bw->favicon);
-
- nsurl_unref(nsurl);
-
- }
-
- }
+ browser_window_update_favicon(c, bw);
history_update(bw->history, c);
hotlist_visited(c);
@@ -1145,13 +1192,26 @@ nserror browser_window_callback(hlcache_handle *c,
case CONTENT_MSG_LINK: /* content has an rfc5988 link element */
{
nsurl *nsref = NULL;
- if ((bw->favicon == NULL) &&
- (strstr(event->data.rfc5988_link.rel, "icon") != NULL)) {
- /* its a favicon start a fetch for it */
- LOG(("fetching favicon rel:%s '%s'",
- event->data.rfc5988_link.rel,
- nsurl_access(event->data.rfc5988_link.url)));
- hlcache_handle_retrieve(event->data.rfc5988_link.url,
+ lwc_string *icon_str;
+ lwc_string *shortcut_icon_str;
+ bool icon_match;
+ bool shortcut_icon_match;
+
+ lwc_intern_string("icon", SLEN("icon"), &icon_str);
+ lwc_intern_string("shortcut icon", SLEN("shortcut_icon"), &shortcut_icon_str);
+ lwc_string_caseless_isequal(event->data.rfc5988_link->rel, icon_str, &icon_match);
+ lwc_string_caseless_isequal(event->data.rfc5988_link->rel, shortcut_icon_str, &shortcut_icon_match);
+ lwc_string_unref(icon_str);
+ lwc_string_unref(shortcut_icon_str);
+
+ if ((bw->loading_favicon == NULL) &&
+ (icon_match || shortcut_icon_match)) {
+ /* its a favicon and we are not already fetching one
+ start a fetch for it */
+ LOG(("fetching favicon rel:%p '%s'",
+ event->data.rfc5988_link->rel,
+ nsurl_access(event->data.rfc5988_link->href)));
+ hlcache_handle_retrieve(event->data.rfc5988_link->href,
HLCACHE_RETRIEVE_MAY_DOWNLOAD |
HLCACHE_RETRIEVE_SNIFF_TYPE,
nsref,
@@ -1160,7 +1220,7 @@ nserror browser_window_callback(hlcache_handle *c,
bw,
NULL,
CONTENT_IMAGE,
- &bw->favicon);
+ &bw->loading_favicon);
}
}
break;
@@ -1724,16 +1784,21 @@ void browser_window_destroy_internal(struct browser_window *bw)
bw->current_content = NULL;
}
- if (bw->favicon != NULL) {
- content_status status =
- content_get_status(bw->favicon);
+ if (bw->loading_favicon != NULL) {
+ hlcache_handle_abort(bw->loading_favicon);
+ hlcache_handle_release(bw->loading_favicon);
+ bw->loading_favicon = NULL;
+ }
+
+ if (bw->current_favicon != NULL) {
+ content_status status = content_get_status(bw->current_favicon);
if (status == CONTENT_STATUS_READY ||
status == CONTENT_STATUS_DONE)
- content_close(bw->favicon);
+ content_close(bw->current_favicon);
- hlcache_handle_release(bw->favicon);
- bw->favicon = NULL;
+ hlcache_handle_release(bw->current_favicon);
+ bw->current_favicon = NULL;
}
if (bw->box != NULL) {
diff --git a/desktop/browser.h b/desktop/browser.h
index c96c4f177..e990f1173 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -76,7 +76,9 @@ struct browser_window {
struct hlcache_handle *loading_content;
/** Page Favicon */
- struct hlcache_handle *favicon;
+ struct hlcache_handle *current_favicon;
+ /** handle for favicon which we started loading early */
+ struct hlcache_handle *loading_favicon;
/** Window history structure. */
struct history *history;
diff --git a/image/image_cache.c b/image/image_cache.c
index 9a478a605..32fe74571 100644
--- a/image/image_cache.c
+++ b/image/image_cache.c
@@ -283,7 +283,7 @@ static void image_cache__background_update(void *p)
}
/* exported interface documented in image_cache.h */
-struct bitmap *image_cache_get_bitmap(struct content *c)
+struct bitmap *image_cache_get_bitmap(const struct content *c)
{
struct image_cache_entry_s *centry;
@@ -576,14 +576,7 @@ void image_cache_destroy(struct content *content)
void *image_cache_get_internal(const struct content *c, void *context)
{
- struct image_cache_entry_s *centry;
-
- centry = image_cache__find(c);
- if (centry == NULL) {
- return NULL;
- }
-
- return centry->bitmap;
+ return image_cache_get_bitmap(c);
}
content_type image_cache_content_type(void)
diff --git a/image/image_cache.h b/image/image_cache.h
index 568f3e951..e879c740d 100644
--- a/image/image_cache.h
+++ b/image/image_cache.h
@@ -79,7 +79,7 @@ nserror image_cache_remove(struct content *content);
/** Obtain a bitmap from a content converting from source if neccessary. */
-struct bitmap *image_cache_get_bitmap(struct content *c);
+struct bitmap *image_cache_get_bitmap(const struct content *c);
/** Obtain a bitmap from a content with no conversion */
struct bitmap *image_cache_find_bitmap(struct content *c);
diff --git a/render/html.c b/render/html.c
index 4c08a6620..09efb3600 100644
--- a/render/html.c
+++ b/render/html.c
@@ -740,6 +740,78 @@ void html_box_convert_done(html_content *c, bool success)
}
+/** process link node */
+static bool html_process_link(html_content *c, xmlNode *node)
+{
+ struct content_rfc5988_link *link;
+ char *xmlstr;
+ nserror error;
+ lwc_string *rel;
+ nsurl *href;
+
+ /* check that the relation exists - w3c spec says must be present */
+ xmlstr = (char *)xmlGetProp(node, (const xmlChar *)"rel");
+ if (xmlstr == NULL) {
+ return false;
+ }
+ lwc_intern_string(xmlstr, strlen(xmlstr), &rel);
+ xmlFree(xmlstr);
+
+ /* check that the href exists - w3c spec says must be present */
+ xmlstr = (char *)xmlGetProp(node, (const xmlChar *) "href");
+ if (xmlstr == NULL) {
+ return false;
+ }
+ error = nsurl_join(c->base_url, xmlstr, &href);
+ xmlFree(xmlstr);
+ if (error != NSERROR_OK) {
+ lwc_string_unref(rel);
+ return false;
+ }
+
+ link = calloc(1, sizeof(struct content_rfc5988_link));
+ if (link == NULL) {
+ lwc_string_unref(rel);
+ nsurl_unref(href);
+ return false;
+ }
+ link->rel = rel;
+ link->href = href;
+
+ /* look for optional properties */
+ xmlstr = (char *)xmlGetProp(node, (const xmlChar *) "hreflang");
+ if (xmlstr != NULL) {
+ lwc_intern_string(xmlstr, strlen(xmlstr), &link->hreflang);
+ xmlFree(xmlstr);
+ }
+
+ xmlstr = (char *) xmlGetProp(node, (const xmlChar *) "type");
+ if (xmlstr != NULL) {
+ lwc_intern_string(xmlstr, strlen(xmlstr), &link->type);
+ xmlFree(xmlstr);
+ }
+
+ xmlstr = (char *) xmlGetProp(node, (const xmlChar *) "media");
+ if (xmlstr != NULL) {
+ lwc_intern_string(xmlstr, strlen(xmlstr), &link->media);
+ xmlFree(xmlstr);
+ }
+
+ xmlstr = (char *) xmlGetProp(node, (const xmlChar *) "sizes");
+ if (xmlstr != NULL) {
+ lwc_intern_string(xmlstr, strlen(xmlstr), &link->sizes);
+ xmlFree(xmlstr);
+ }
+
+ /* add to content */
+ content__add_rfc5988_link(&c->base, link);
+
+ /* release this copy */
+ content__free_rfc5988_link(link);
+
+ return true;
+}
+
/**
* Process elements in <head>.
*
@@ -811,34 +883,7 @@ bool html_head(html_content *c, xmlNode *head)
xmlFree(s);
}
} else if (strcmp((const char *) node->name, "link") == 0) {
- union content_msg_data msg_data;
- char *href;
- nserror error;
-
- href = (char *) xmlGetProp(node, (const xmlChar *) "href");
- if (href) {
- error = nsurl_join(c->base_url, href, &msg_data.rfc5988_link.url);
-
- xmlFree(href);
- }
-
- msg_data.rfc5988_link.rel = (char *)xmlGetProp(node,
- (const xmlChar *)"rel");
- msg_data.rfc5988_link.type = (char *)xmlGetProp(node,
- (const xmlChar *)"type");
-
- content_broadcast(&c->base, CONTENT_MSG_LINK, msg_data);
-
- if (error == NSERROR_OK) {
- nsurl_unref(msg_data.rfc5988_link.url);
- }
- if (msg_data.rfc5988_link.rel) {
- xmlFree(msg_data.rfc5988_link.rel);
- }
- if (msg_data.rfc5988_link.type) {
- xmlFree(msg_data.rfc5988_link.type);
- }
-
+ html_process_link(c, node);
}
}
return true;