> Index: render/favicon.c > the favicon branch is the origin of these changes; the branch adds a favicon to the toolbar beside the url bar; as well as the gtk front code to add the widget to the toolbar, there is core code to retrieve the favicon; essentially there are 2 stages, 1 retrieve a favicon reference from the html of the page [default to domain/favicon.ico], 2 retrieve the favicon from the web [/from cache]; [then stage 3 is update the toolbar once the favicon is retrieved]
render/favicon.c accomplishes stages 1-2, stage 1 involves searching the xml tree, looking for a 'link' node as the code looks for css 'link' nodes, checking for 'rel' attribute, comparing it to precomputed hashes of normal rel strings for favicons, scoring the references according to a generally web-standards oriented scoring system, then picking the highest-scoring favicon; a fetchcache() call is made, then when the favicon is retrieved it may be added to the toolbar; > =================================================================== > --- /dev/null 2009-04-16 19:17:07.000000000 +0100 > +++ render/favicon.c 2009-07-10 12:49:13.000000000 +0100 > @@ -0,0 +1,375 @@ > +/* > + * Copyright 2007 James Bursa <[email protected]> > + * Copyright 2009 Mark Benjamin <[email protected]> > + * > + * This file is part of NetSurf, http://www.netsurf-browser.org/ > + * > + * NetSurf is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * NetSurf is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <string.h> > +#include "content/fetch.h" > +#include "content/fetchcache.h" > +#include "render/favicon.h" > +#include "render/html.h" > +#include "utils/log.h" > +#include "utils/messages.h" > +#include "utils/talloc.h" > +#include "utils/url.h" > +#include "utils/utils.h" > + > +static char *favicon_get_icon_ref(struct content *c, xmlNode *html); > +static void favicon_callback(content_msg msg, struct content *icon, > + intptr_t p1, intptr_t p2, union content_msg_data data); > +static unsigned long favicon_hash(char *str); > + > +unsigned long favicon_hash(char *str) > +{ > + if (str == NULL) > + return 0; > + unsigned long hash = 5381; > + int c; > + while ((c = (unsigned char) *str++)) > + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ > + return hash; > +} > + > +/** > + * retrieve 1 url reference to 1 favicon > + * \param html xml node of html element > + * \return pointer to url; NULL for no icon > + */ > +char *favicon_get_icon_ref(struct content *c, xmlNode *html) > +{ > + xmlNode *node; > + char *rel, *type, *href, *url, *suf, *url2; > + url2 = NULL; > + url_func_result res; > + int score, hiscore; > + hiscore = 0; > + /* hashed values - saves calculating them afresh every time */ > + #define HHICON 0x7c98572e > + /* icon */ > + #define HHSHORTCUTICON 0xfcbccdca > + /* shortcut icon */ > + #define HHAPPLETOUCHICON 0x024c6ddd > + /* apple-touch-icon */ > + #define HHIMAGEPNG 0x7382417c > + /* image/png */ > + #define HHIMAGEGIF 0x73821a8d > + /* image/gif */ > + #define HHIMAGEVNDMICROSOFTICON 0xdae02bba > + /* image.vnd.microsoft.icon */ > + #define HHIMAGEJPEG 0xe3c72f5d > + /* image/jpeg */ > + #define HHIMAGEJPG 0x73822838 > + /* image/jpg */ > + #define HHIMAGEICO 0x73822252 > + /* image/ico */ > + #define HHIMAGEICON 0xe3c66d00 > + /* image/icon */ > + #define HHIMAGEXICON 0x0e3e78e5 > + /* image/x-icon */ > + #define HHTEXTICO 0x17e966a2 > + /* text/icon */ > + #define HHAPPLICATIONICO 0x087b6fb4 > + /*application/icon*/ > + #define HHSUFICO 0x0b887ec0 > + /* ico */ > + #define HHSUFPNG 0x0b889dea > + /* png */ > + #define HHSUFGIF 0x0b8876fb > + /* gif */ > + #define HHSUFJPG 0x0b888486 > + /* jpg */ > + #define HHSUFJPEG 0x7c99198b > + /* jpeg */ > + > + union content_msg_data msg_data; > + > + node = html; > + while (node) { > + score = 0; > + suf = NULL; > + if (node->children) { /* children */ > + node = node->children; > + } else if (node->next) { /* siblings */ > + node = node->next; > + } else { /* ancestor siblings */ > + while (node && !node->next) > + node = node->parent; > + if (!node) > + break; > + node = node->next; > + } > + assert(node); > + > + if (node->type != XML_ELEMENT_NODE) > + continue; > + > + if (strcmp((const char *) node->name, "link") == 0) { > + /* rel=<space separated list, including 'icon'> */ > + if ((rel = (char *) xmlGetProp(node, > + (const xmlChar *) "rel")) == NULL) > + continue; > + if (strcasestr(rel, "icon") == 0) { > + xmlFree(rel); > + continue; > + } > + LOG(("icon node found")); > + switch(favicon_hash(rel)) { > + /* give points for rel attributes, kind of arbitrary > + * in an attempt to test how closely standards are > + * being respected; the reason apple-touch-icon scores > + * less is that the appearance of such is really > + * specific to the iphone style */ > + case HHICON: > + LOG(("icon")); > + score = 3; > + break; > + case HHSHORTCUTICON: > + LOG(("shortcut icon")); > + score = 5; > + break; > + case HHAPPLETOUCHICON: > + LOG(("apple-touch-icon")); > + score = 1; > + break; > + } > + xmlFree(rel); > + /* current implementation scores candidates according > + * to how closely they seem to adhere to standards, > + * scoring system may be modified in the future */ > + if ((type = (char *) xmlGetProp(node, > + (const xmlChar *) "type")) != NULL) { > + switch(favicon_hash(type)) { > + /* here we score highest for "image/type" > + * mime types, lower scores for "type/ico" > + * mime types, no score for no type */ > + case HHIMAGEPNG: > + score += 5; > + break; > + case HHIMAGEGIF: > + score += 5; > + break; > + case HHIMAGEVNDMICROSOFTICON: > + score += 5; > + break; > + case HHIMAGEJPEG: > + score += 5; > + break; > + case HHIMAGEJPG: > + score += 5; > + break; > + case HHIMAGEICO: > + score += 5; > + break; > + case HHIMAGEICON: > + score += 5; > + break; > + case HHIMAGEXICON: > + score += 5; > + break; > + case HHTEXTICO: > + score += 2; > + break; > + case HHAPPLICATIONICO: > + score += 1; > + break; > + } > + xmlFree(type); > + } > + if ((href = (char *) xmlGetProp(node, > + (const xmlChar *) "href")) == NULL) > + continue; > + suf = strrchr(href, '.'); > + if (suf != NULL) { > + suf ++; > + switch(favicon_hash(suf)) { > + /* here the largest bonus points of all > + * attributes, notably for .ico, .png, .gif > + * as the standards support; less for .jpg */ > + case HHSUFICO: > + score += 10; > + break; > + case HHSUFPNG: > + score += 10; > + break; > + case HHSUFGIF: > + score += 10; > + break; > + case HHSUFJPG: > + score += 7; > + break; > + case HHSUFJPEG: > + score += 7; > + break; > + } > + } > + if (score > hiscore) { > + res = url_join(href, c->data.html.base_url, > + &url); > + xmlFree(href); > + if (res != URL_FUNC_OK) > + continue; > + > + LOG(("best favicon so far '%s'", url)); > + res = url_normalize(url, &url2); > + if (res != URL_FUNC_OK) { > + url2 = NULL; > + if (res == URL_FUNC_NOMEM) > + goto no_memory; > + continue; > + } > + hiscore = score; > + free(url); > + } > + } > + } > + if (url2 == NULL) { > + struct url_components comp; > + if (url_get_components(c->data.html.base_url, &comp) != > + URL_FUNC_OK) > + return NULL; > + if (url_normalize(comp.authority, > + &url) != URL_FUNC_OK) > + return NULL; > + url_destroy_components(&comp); > + if (url_join("/favicon.ico", url, &url2) != URL_FUNC_OK) > + return NULL; > + free(url); > + } > + LOG(("Best favicon %s", url2)); > + return url2; > +no_memory: > + msg_data.error = messages_get("NoMemory"); > + /* content_broadcast(c, CONTENT_MSG_ERROR, msg_data); */ > + return false; > +} > + > +/** > + * retrieve 1 favicon > + * \param c content structure > + * \param html xml node of html element > + * \return true for success, false for error > + */ > + > +bool favicon_get_icon(struct content *c, xmlNode *html) > +{ > + union content_msg_data msg_data; > + char *url = favicon_get_icon_ref(c, html); > + struct content *favcontent = NULL; > + if (url != NULL) > + favcontent = fetchcache(url, favicon_callback, > + (intptr_t) c, 0, c->width, c->height, true, 0, > + 0, false, false); > + free(url); > + if (favcontent == NULL) > + return false; > + > + c->data.html.favicon = favcontent; > + > + fetchcache_go(favcontent, c->url, favicon_callback, > + (intptr_t) c, 0, c->width, c->height, > + 0, 0, false, c->url); > + > + if (!c->data.html.favicon) { > + msg_data.error = "Favicon failed to load"; > + return false; > + } > + return true; > +} > + > +/** > + * Callback for fetchcache() for linked favicon > + */ > + > +void favicon_callback(content_msg msg, struct content *icon, > + intptr_t p1, intptr_t p2, union content_msg_data data) > +{ > + struct content *c = (struct content *) p1; > + unsigned int i = p2; > + > + switch (msg) { > + case CONTENT_MSG_LOADING: > + /* check that the favicon is really a correct image type */ > + > + if (!((icon->type == CONTENT_ICO) || > + (icon->type == CONTENT_PNG) || > + (icon->type == CONTENT_GIF))) { > + c->data.html.favicon = 0; > + LOG(("%s is not a favicon", icon->url)); > + content_add_error(c, "NotFavIco", 0); > + html_set_status(c, messages_get("NotFavIco")); > + content_broadcast(c, CONTENT_MSG_STATUS, data); > + content_remove_user(icon, > + favicon_callback, > + (intptr_t) c, i); > + if (!icon->user_list->next) { > + /* we were the only user and we don't want this > + * content, so stop it fetching and mark it as > + * having an error so it gets removed from the > + * cache next time content_clean() gets called > + */ > + fetch_abort(icon->fetch); > + icon->fetch = 0; > + icon->status = CONTENT_STATUS_ERROR; > + } > + } > + break; > + > + case CONTENT_MSG_READY: > + break; > + > + case CONTENT_MSG_DONE: > + LOG(("got favicon '%s'", icon->url)); > + break; > + > + case CONTENT_MSG_LAUNCH: > + /* Fall through */ > + case CONTENT_MSG_ERROR: > + LOG(("favicon %s failed: %s", icon->url, data.error)); > + /* The favicon we were fetching may have been > + * redirected, in that case, the object pointers > + * will differ, so ensure that the object that's > + * in error is still in use by us before invalidating > + * the pointer */ > + if (c->data.html.favicon == icon) { > + c->data.html.favicon = 0; > + content_add_error(c, "?", 0); > + } > + break; > + > + case CONTENT_MSG_STATUS: > + html_set_status(c, icon->status_message); > + content_broadcast(c, CONTENT_MSG_STATUS, data); > + break; > + > + case CONTENT_MSG_NEWPTR: > + c->data.html.favicon = icon; > + break; > + > + case CONTENT_MSG_AUTH: > + c->data.html.favicon = 0; > + content_add_error(c, "?", 0); > + break; > + > + case CONTENT_MSG_SSL: > + c->data.html.favicon = 0; > + content_add_error(c, "?", 0); > + break; > + > + default: > + assert(0); > + } > +} > Index: render/favicon.h > =================================================================== > --- /dev/null 2009-04-16 19:17:07.000000000 +0100 > +++ render/favicon.h 2009-07-10 12:49:13.000000000 +0100 > @@ -0,0 +1,63 @@ > +/* > + * Copyright 2009 Mark Benjamin <[email protected]> > + * > + * This file is part of NetSurf, http://www.netsurf-browser.org/ > + * > + * NetSurf is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * NetSurf is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef _NETSURF_RENDER_FAVICON_H_ > +#define _NETSURF_RENDER_FAVICON_H_ > + > +typedef enum { > + HHICON = 0x7c98572e, > + /* icon */ > + HHSHORTCUTICON = 0xfcbccdca, > + /* shortcut icon */ > + HHAPPLETOUCHICON = 0x024c6ddd, > + /* apple-touch-icon */ > + HHIMAGEPNG = 0x7382417c, > + /* image/png */ > + HHIMAGEGIF = 0x73821a8d, > + /* image/gif */ > + HHIMAGEVNDMICROSOFTICON = 0xdae02bba, > + /* image.vnd.microsoft.icon */ > + HHIMAGEJPEG = 0xe3c72f5d, > + /* image/jpeg */ > + HHIMAGEJPG = 0x73822838, > + /* image/jpg */ > + HHIMAGEICO = 0x73822252, > + /* image/ico */ > + HHIMAGEICON = 0xe3c66d00, > + /* image/icon */ > + HHIMAGEXICON = 0x0e3e78e5, > + /* image/x-icon */ > + HHTEXTICO = 0x17e966a2, > + /* text/icon */ > + HHAPPLICATIONICO = 0x087b6fb4, > + /* application/icon */ > + HHSUFICO = 0x0b887ec0, > + /* ico */ > + HHSUFPNG = 0x0b889dea, > + /* png */ > + HHSUFGIF = 0x0b8876fb, > + /* gif */ > + HHSUFJPG = 0x0b888486, > + /* jpg */ > + HHSUFJPEG = 0x7c99198b > + /* jpeg */ > +} favicon_string_hash; > + > +bool favicon_get_icon(struct content *c, xmlNode *html); > + > +#endif > Index: render/html.c > changes from favicon branch; addition of favicon element to html content; call to retrieve favicon when loading page; > =================================================================== > --- render/html.c (revision 8438) > +++ render/html.c (working copy) > @@ -37,6 +37,7 @@ > #include "desktop/options.h" > #include "image/bitmap.h" > #include "render/box.h" > +#include "render/favicon.h" > #include "render/font.h" > #include "render/form.h" > #include "render/html.h" > @@ -73,7 +74,6 @@ > static void html_object_refresh(void *p); > static void html_destroy_frameset(struct content_html_frames *frameset); > static void html_destroy_iframe(struct content_html_iframe *iframe); > -static void html_set_status(struct content *c, const char *extra); > #if ALWAYS_DUMP_FRAMESET > static void html_dump_frameset(struct content_html_frames *frame, > unsigned int depth); > @@ -283,6 +283,7 @@ > * > * - parsing to an XML tree is completed > * - stylesheets are fetched > + * - favicon is retrieved > * - the XML tree is converted to a box tree and object fetches are started > * - the box tree is laid out > * > @@ -399,6 +400,9 @@ > if (!html_find_stylesheets(c, html)) > return false; > > + /* get icon */ > + favicon_get_icon(c, html); > + > /* Retrieve forms from parser */ > c->data.html.forms = binding_get_forms(c->data.html.parser_binding); > for (f = c->data.html.forms; f != NULL; f = f->prev) { > @@ -765,7 +769,7 @@ > * Uses STYLE and LINK elements inside and outside HEAD > * > * \param c content structure > - * \param head xml node of html element > + * \param html xml node of html element > * \return true on success, false if an error occurred > */ > > Index: render/html.h > =================================================================== > --- render/html.h (revision 8438) > +++ render/html.h (working copy) > @@ -128,6 +128,8 @@ > colour background_colour; /**< Document background colour. */ > const struct font_functions *font_func; > > + struct content *favicon; > + > /** Number of entries in stylesheet_content. */ > unsigned int stylesheet_count; > /** Stylesheets. Each may be 0. */ > @@ -184,6 +186,7 @@ > struct content *page, unsigned int index, struct box *box, > struct object_params *params); > void html_close(struct content *c); > +void html_set_status(struct content *c, const char *extra); > > /* in render/html_redraw.c */ > bool html_redraw(struct content *c, int x, int y, > Index: image/ico.c > from favicon branch additional assistance function to set ico size > =================================================================== > --- image/ico.c (revision 8438) > +++ image/ico.c (working copy) > @@ -114,6 +114,15 @@ > background_colour, BITMAPF_NONE); > } > > +bool nsico_set_bitmap_from_size(struct content *c, int width, int height) > +{ > + struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height); > + if (!bmp->decoded) > + if (bmp_decode(bmp) != BMP_OK) > + return false; > + c->bitmap = bmp->bitmap; > + return true; > +} > > bool nsico_redraw_tiled(struct content *c, int x, int y, > int width, int height, > Index: image/ico.h > =================================================================== > --- image/ico.h (revision 8438) > +++ image/ico.h (working copy) > @@ -47,6 +47,7 @@ > int clip_x0, int clip_y0, int clip_x1, int clip_y1, > float scale, colour background_colour, > bool repeat_x, bool repeat_y); > +bool nsico_set_bitmap_from_size(struct content *c, int width, int height); > > #endif /* WITH_BMP */ > > Index: beos/beos_scaffolding.cpp > =================================================================== > --- beos/beos_scaffolding.cpp (revision 8438) > +++ beos/beos_scaffolding.cpp (working copy) > @@ -2311,6 +2311,10 @@ > g->top_view->UnlockLooper(); > } > > +void gui_window_set_icon(struct gui_window *g, struct content *icon) > +{ > +} > + > #warning XXX > #if 0 /* GTK */ > gboolean nsbeos_scaffolding_is_busy(nsbeos_scaffolding *scaffold) > Index: riscos/window.c > function stubs for favicon branch / search branch > =================================================================== > --- riscos/window.c (revision 8438) > +++ riscos/window.c (working copy) > @@ -1104,8 +1104,21 @@ > } > } > > +/** > + * set favicon > + */ > +void gui_window_set_icon(struct gui_window *g, struct content *icon) > +{ > +} > > /** > + * set the search provider icon from global cache struct content *search_ico > + */ > +void gui_window_set_search_ico() > +{ > +} > + > +/** > * Place the caret in a browser window. > * > * \param g window with caret > Index: desktop/gui.h > =================================================================== > --- desktop/gui.h (revision 8438) > +++ desktop/gui.h (working copy) > @@ -57,8 +57,6 @@ > #include "content/content.h" > #include "desktop/browser.h" > > -extern struct gui_window *search_current_window; > - > void gui_init(int argc, char** argv); > void gui_init2(int argc, char** argv); > void gui_multitask(void); > @@ -67,6 +65,7 @@ > > struct gui_window *gui_create_browser_window(struct browser_window *bw, > struct browser_window *clone, bool new_tab); > +struct browser_window *gui_window_get_browser_window(struct gui_window *g); > void gui_window_destroy(struct gui_window *g); > void gui_window_set_title(struct gui_window *g, const char *title); > void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1); > @@ -88,6 +87,8 @@ > void gui_window_set_url(struct gui_window *g, const char *url); > void gui_window_start_throbber(struct gui_window *g); > void gui_window_stop_throbber(struct gui_window *g); > +void gui_window_set_icon(struct gui_window *g, struct content *icon); > +void gui_window_set_search_ico(void); > void gui_window_place_caret(struct gui_window *g, int x, int y, int height); > void gui_window_remove_caret(struct gui_window *g); > void gui_window_new_content(struct gui_window *g); > Index: content/content.c > =================================================================== > --- content/content.c (revision 8438) > +++ content/content.c (working copy) > @@ -155,6 +155,9 @@ > {"image/svg", CONTENT_SVG}, > {"image/svg+xml", CONTENT_SVG}, > #endif > +#ifdef WITH_BMP > + {"image/vnd.microsoft.icon", CONTENT_ICO}, > +#endif > #ifdef WITH_ARTWORKS > {"image/x-artworks", CONTENT_ARTWORKS}, > #endif > Index: amiga/gui.c > =================================================================== > --- amiga/gui.c (revision 8438) > +++ amiga/gui.c (working copy) > @@ -46,6 +46,7 @@ > #include "amiga/menu.h" > #include "amiga/options.h" > #include <libraries/keymap.h> > +#include "desktop/save_complete.h" > #include "desktop/textinput.h" > #include <intuition/pointerclass.h> > #include <math.h> > @@ -65,7 +66,6 @@ > #include "amiga/cookies.h" > #include "amiga/clipboard.h" > #include <proto/keymap.h> > -#include "amiga/save_complete.h" > #include "amiga/fetch_file.h" > #include "amiga/fetch_mailto.h" > #include "amiga/search.h" > @@ -2787,6 +2787,10 @@ > g->shared->throbber_frame = 0; > } > > +void gui_window_set_icon(struct gui_window *g, struct content *icon) > +{ > +} > + > void ami_update_throbber(struct gui_window_2 *g,bool redraw) > { > struct IBox *bbox; Mark http://www.halloit.com Key ID 046B65CF
