summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2006-03-25 20:30:35 +0000
committerJames Bursa <james@netsurf-browser.org>2006-03-25 20:30:35 +0000
commit5a72700817565b139e9576738d5b1ec23e23e69e (patch)
treeb578ef82e56785c328db1410e90ca1e065858432 /desktop
parent016128c37dc80b26851870d72d329f0579423ece (diff)
downloadnetsurf-5a72700817565b139e9576738d5b1ec23e23e69e.tar.gz
netsurf-5a72700817565b139e9576738d5b1ec23e23e69e.tar.bz2
[project @ 2006-03-25 20:30:35 by bursa]
Split local history into portable and RISC OS specific code. Improve layout of history tree. svn path=/import/netsurf/; revision=2164
Diffstat (limited to 'desktop')
-rw-r--r--desktop/browser.c3
-rw-r--r--desktop/browser.h16
-rw-r--r--desktop/history_core.c545
-rw-r--r--desktop/history_core.h36
4 files changed, 588 insertions, 12 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index b709ba289..031089b9d 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -29,6 +29,7 @@
#include "netsurf/desktop/401login.h"
#endif
#include "netsurf/desktop/browser.h"
+#include "netsurf/desktop/history_core.h"
#include "netsurf/desktop/gui.h"
#include "netsurf/desktop/options.h"
#include "netsurf/desktop/selection.h"
@@ -173,6 +174,8 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
char url_buf[256];
LOG(("bw %p, url %s", bw, url));
+ assert(bw);
+ assert(url);
res = url_normalize(url, &url2);
if (res != URL_FUNC_OK) {
diff --git a/desktop/browser.h b/desktop/browser.h
index 67da0abea..642512592 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -3,7 +3,7 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
*/
/** \file
@@ -150,22 +150,14 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
/* In platform specific hotlist.c. */
void hotlist_visited(struct content *content);
-/* In platform specific history.c. */
-struct history *history_create(void);
-void history_add(struct history *history, struct content *content,
- char *frag_id);
-void history_update(struct history *history, struct content *content);
-void history_destroy(struct history *history);
-void history_back(struct browser_window *bw, struct history *history);
-void history_forward(struct browser_window *bw, struct history *history);
-bool history_back_available(struct history *history);
-bool history_forward_available(struct history *history);
-
/* In platform specific global_history.c. */
void global_history_add(struct url_content *data);
void global_history_add_recent(const char *url);
char **global_history_get_recent(int *count);
+/* In platform specific thumbnail.c. */
+bool thumbnail_create(struct content *content, struct bitmap *bitmap,
+ const char *url);
/* In platform specific schedule.c. */
void schedule(int t, void (*callback)(void *p), void *p);
diff --git a/desktop/history_core.c b/desktop/history_core.c
new file mode 100644
index 000000000..04e02d736
--- /dev/null
+++ b/desktop/history_core.c
@@ -0,0 +1,545 @@
+/*
+ * 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 2006 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ */
+
+/** \file
+ * Browser history tree (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "netsurf/content/content.h"
+#include "netsurf/content/url_store.h"
+#include "netsurf/css/css.h"
+#include "netsurf/desktop/gui.h"
+#include "netsurf/desktop/history_core.h"
+#include "netsurf/desktop/plotters.h"
+#include "netsurf/image/bitmap.h"
+#include "netsurf/render/font.h"
+#include "netsurf/utils/log.h"
+#include "netsurf/utils/url.h"
+#include "netsurf/utils/utils.h"
+
+
+#define WIDTH 100
+#define HEIGHT 86
+#define RIGHT_MARGIN 50
+#define BOTTOM_MARGIN 30
+
+
+/** A node in the history tree. */
+struct history_entry {
+ char *url; /**< Page URL. */
+ char *frag_id; /** Fragment identifier */
+ char *title; /**< Page title. */
+ struct history_entry *back; /**< Parent. */
+ struct history_entry *next; /**< Next sibling. */
+ struct history_entry *forward; /**< First child. */
+ struct history_entry *forward_pref; /**< Child in direction of
+ current entry. */
+ struct history_entry *forward_last; /**< Last child. */
+ unsigned int children; /**< Number of children. */
+ int x; /**< Position of node. */
+ int y; /**< Position of node. */
+ struct bitmap *bitmap; /**< Thumbnail bitmap, or 0. */
+};
+
+/** History tree for a window. */
+struct history {
+ /** First page in tree (page that window opened with). */
+ struct history_entry *start;
+ /** Current position in tree. */
+ struct history_entry *current;
+ /** Width of layout. */
+ int width;
+ /** Height of layout. */
+ int height;
+};
+
+static void history_free_entry(struct history_entry *entry);
+static void history_go(struct browser_window *bw, struct history *history,
+ struct history_entry *entry, bool new_window);
+static void history_layout(struct history *history);
+static int history_layout_subtree(struct history *history,
+ struct history_entry *entry, int x, int y, bool shuffle);
+static bool history_redraw_entry(struct history *history,
+ struct history_entry *entry);
+static struct history_entry *history_find_position(struct history_entry *entry,
+ int x, int y);
+
+
+/**
+ * Create a new history tree for a window.
+ *
+ * \return pointer to an opaque history structure, 0 on failure.
+ */
+
+struct history *history_create(void)
+{
+ struct history *history;
+
+ history = malloc(sizeof *history);
+ if (!history) {
+ warn_user("NoMemory", 0);
+ return 0;
+ }
+
+ history->start = 0;
+ history->current = 0;
+
+ return history;
+}
+
+
+/**
+ * Insert a url into the history tree.
+ *
+ * \param history opaque history structure, as returned by history_create()
+ * \param content content to add to history
+ * \param frag_id fragment identifier
+ *
+ * The page is added after the current entry and becomes current.
+ */
+
+void history_add(struct history *history, struct content *content,
+ char *frag_id)
+{
+ url_func_result res;
+ struct history_entry *entry;
+ char *url;
+ char *title;
+ struct bitmap *bitmap;
+
+ assert(history);
+ assert(content);
+
+ /* allocate space */
+ entry = malloc(sizeof *entry);
+ res = url_normalize(content->url, &url);
+ if (res != URL_FUNC_OK) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+ title = strdup(content->title ? content->title : url);
+ if (!entry || !url || !title) {
+ warn_user("NoMemory", 0);
+ free(entry);
+ free(url);
+ free(title);
+ return;
+ }
+
+ entry->url = url;
+ entry->frag_id = frag_id ? strdup(frag_id) : 0;
+ entry->title = title;
+ entry->back = history->current;
+ entry->next = 0;
+ entry->forward = entry->forward_pref = entry->forward_last = 0;
+ entry->children = 0;
+ entry->bitmap = 0;
+ if (history->current) {
+ if (history->current->forward_last)
+ history->current->forward_last->next = entry;
+ else
+ history->current->forward = entry;
+ history->current->forward_pref = entry;
+ history->current->forward_last = entry;
+ history->current->children++;
+ } else {
+ history->start = entry;
+ }
+ history->current = entry;
+
+ /* if we have a thumbnail, don't update until the page has finished
+ * loading */
+ bitmap = url_store_get_thumbnail(url);
+ if (!bitmap) {
+ bitmap = bitmap_create(WIDTH, HEIGHT,
+ BITMAP_NEW | BITMAP_CLEAR_MEMORY |
+ BITMAP_OPAQUE | BITMAP_PERSISTENT);
+ if (!bitmap) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+ thumbnail_create(content, bitmap, url);
+ }
+ entry->bitmap = bitmap;
+
+ history_layout(history);
+}
+
+
+/**
+ * Update the thumbnail for the current entry.
+ *
+ * \param history opaque history structure, as returned by history_create()
+ * \param content content for current entry
+ */
+
+void history_update(struct history *history, struct content *content)
+{
+ if (!history || !history->current || !history->current->bitmap)
+ return;
+
+ thumbnail_create(content, history->current->bitmap, 0);
+}
+
+
+/**
+ * Free a history structure.
+ *
+ * \param history opaque history structure, as returned by history_create()
+ */
+
+void history_destroy(struct history *history)
+{
+ if (!history)
+ return;
+ history_free_entry(history->start);
+ free(history);
+}
+
+
+/**
+ * Free an entry in the tree recursively.
+ */
+
+void history_free_entry(struct history_entry *entry)
+{
+ if (!entry)
+ return;
+ history_free_entry(entry->forward);
+ history_free_entry(entry->next);
+ free(entry->url);
+ if (entry->frag_id)
+ free(entry->frag_id);
+ free(entry->title);
+ free(entry);
+}
+
+
+/**
+ * Go back in the history.
+ *
+ * \param bw browser window
+ * \param history history of the window
+ */
+
+void history_back(struct browser_window *bw, struct history *history)
+{
+ if (!history || !history->current || !history->current->back)
+ return;
+ history_go(bw, history, history->current->back, false);
+}
+
+
+/**
+ * Go forward in the history.
+ *
+ * \param bw browser window
+ * \param history history of the window
+ */
+
+void history_forward(struct browser_window *bw, struct history *history)
+{
+ if (!history || !history->current || !history->current->forward_pref)
+ return;
+ history_go(bw, history, history->current->forward_pref, false);
+}
+
+
+/**
+ * Check whether it is pssible to go back in the history.
+ *
+ * \param history history of the window
+ * \return true if the history can go back, false otherwise
+ */
+
+bool history_back_available(struct history *history)
+{
+ return (history && history->current && history->current->back);
+}
+
+
+/**
+ * Check whether it is pssible to go forwards in the history.
+ *
+ * \param history history of the window
+ * \return true if the history can go forwards, false otherwise
+ */
+
+bool history_forward_available(struct history *history)
+{
+ return (history && history->current && history->current->forward_pref);
+}
+
+
+/**
+ * Open a history entry in the specified browser window
+ *
+ * \param bw browser window
+ * \param history history containing entry
+ * \param entry entry to open
+ * \param new_window open entry in new window
+ */
+
+void history_go(struct browser_window *bw, struct history *history,
+ struct history_entry *entry, bool new_window)
+{
+ char *url;
+
+ if (entry->frag_id) {
+ url = malloc(strlen(entry->url) + strlen(entry->frag_id) + 5);
+ if (!url) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+ sprintf(url, "%s#%s", entry->url, entry->frag_id);
+ }
+ else
+ url = entry->url;
+
+ if (new_window)
+ browser_window_create(url, bw, 0);
+ else {
+ history->current = entry;
+ browser_window_go_post(bw, url, 0, 0, false, 0, false);
+ }
+
+ if (entry->frag_id)
+ free(url);
+}
+
+
+/**
+ * Compute node positions.
+ *
+ * \param history history to layout
+ *
+ * Each node's x and y are filled in.
+ */
+
+void history_layout(struct history *history)
+{
+ time_t t = time(0);
+ struct tm *tp = localtime(&t);
+ bool shuffle = tp->tm_mon == 3 && tp->tm_mday == 1;
+
+ history->width = 0;
+ history->height = history_layout_subtree(history, history->start,
+ RIGHT_MARGIN / 2, BOTTOM_MARGIN / 2, shuffle);
+ if (shuffle) {
+ history->width = 600 + WIDTH;
+ history->height = 400 + HEIGHT;
+ }
+ history->width += RIGHT_MARGIN / 2;
+ history->height += BOTTOM_MARGIN / 2;
+}
+
+
+/**
+ * Recursively position a subtree.
+ *
+ * \param history history being laid out
+ * \param entry subtree to position
+ * \param x x position for entry
+ * \param y smallest available y
+ * \param shuffle shuffle layout
+ * \return greatest y used by subtree
+ */
+
+int history_layout_subtree(struct history *history,
+ struct history_entry *entry, int x, int y, bool shuffle)
+{
+ struct history_entry *child;
+ int y1 = y;
+
+ if (history->width < x + WIDTH)
+ history->width = x + WIDTH;
+
+ if (!entry->forward) {
+ entry->x = x;
+ entry->y = y;
+ if (shuffle) {
+ entry->x = rand() % 600;
+ entry->y = rand() % 400;
+ }
+ return y + HEIGHT;
+ }
+
+ /* layout child subtrees below each other */
+ for (child = entry->forward; child; child = child->next) {
+ y1 = history_layout_subtree(history, child,
+ x + WIDTH + RIGHT_MARGIN, y1, shuffle);
+ if (child->next)
+ y1 += BOTTOM_MARGIN;
+ }
+
+ /* place ourselves in the middle */
+ entry->x = x;
+ entry->y = (y + y1) / 2 - HEIGHT / 2;
+ if (shuffle) {
+ entry->x = rand() % 600;
+ entry->y = rand() % 400;
+ }
+
+ return y1;
+}
+
+
+/**
+ * Get the dimensions of a history.
+ *
+ * \param history history to measure
+ * \param width updated to width
+ * \param height updated to height
+ */
+
+void history_size(struct history *history, int *width, int *height)
+{
+ *width = history->width;
+ *height = history->height;
+}
+
+
+/**
+ * Redraw a history.
+ *
+ * \param history history to render
+ *
+ * The current plotter is used.
+ */
+
+bool history_redraw(struct history *history)
+{
+ if (!history->start)
+ return true;
+ return history_redraw_entry(history, history->start);
+}
+
+
+/**
+ * Recursively redraw a history_entry.
+ *
+ * \param history history containing the entry
+ * \param history_entry entry to render
+ */
+
+bool history_redraw_entry(struct history *history,
+ struct history_entry *entry)
+{
+ size_t char_offset;
+ int actual_x;
+ struct history_entry *child;
+ colour c = entry == history->current ? 0x0000ff : 0x333333;
+
+ if (!plot.bitmap(entry->x, entry->y, WIDTH, HEIGHT, entry->bitmap,
+ 0xffffff))
+ return false;
+ if (!plot.rectangle(entry->x - 1, entry->y - 1, WIDTH + 1, HEIGHT + 1,
+ entry == history->current ? 2 : 1, c, false, false))
+ return false;
+
+ if (!nsfont_position_in_string(&css_base_style, entry->title,
+ strlen(entry->title), WIDTH, &char_offset, &actual_x))
+ return false;
+ if (!plot.text(entry->x, entry->y + HEIGHT + 12, &css_base_style,
+ entry->title, char_offset, 0xffffff, c))
+ return false;
+
+ for (child = entry->forward; child; child = child->next) {
+ if (!plot.line(entry->x + WIDTH, entry->y + HEIGHT / 2,
+ child->x, child->y + HEIGHT / 2, 1,
+ 0x333333, false, false))
+ return false;
+ if (!history_redraw_entry(history, child))
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Handle a mouse click in a history.
+ *
+ * \param bw browser window containing history
+ * \param history history that was clicked in
+ * \param x click coordinate
+ * \param y click coordinate
+ * \param new_window open a new window instead of using bw
+ * \return true if action was taken, false if click was not on an entry
+ */
+
+bool history_click(struct browser_window *bw, struct history *history,
+ int x, int y, bool new_window)
+{
+ struct history_entry *entry;
+
+ entry = history_find_position(history->start, x, y);
+ if (!entry)
+ return false;
+ if (entry == history->current)
+ return false;
+
+ history_go(bw, history, entry, new_window);
+
+ return true;
+}
+
+
+/**
+ * Determine the URL of the entry at a position.
+ *
+ * \param history history to search
+ * \param x coordinate
+ * \param y coordinate
+ * \return URL, or 0 if no entry at (x, y)
+ */
+
+const char *history_position_url(struct history *history, int x, int y)
+{
+ struct history_entry *entry;
+
+ entry = history_find_position(history->start, x, y);
+ if (!entry)
+ return 0;
+
+ return entry->url;
+}
+
+
+/**
+ * Find the history entry at a position.
+ *
+ * \param entry entry to search from
+ * \param x coordinate
+ * \param y coordinate
+ * \return an entry if found, 0 if none
+ */
+
+struct history_entry *history_find_position(struct history_entry *entry,
+ int x, int y)
+{
+ struct history_entry *child;
+ struct history_entry *found;
+
+ if (entry->x <= x && x <= entry->x + WIDTH &&
+ entry->y <= y && y <= entry->y + HEIGHT)
+ return entry;
+
+ for (child = entry->forward; child; child = child->next) {
+ found = history_find_position(child, x, y);
+ if (found)
+ return found;
+ }
+
+ return 0;
+}
diff --git a/desktop/history_core.h b/desktop/history_core.h
new file mode 100644
index 000000000..4889ad524
--- /dev/null
+++ b/desktop/history_core.h
@@ -0,0 +1,36 @@
+/*
+ * 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 2006 James Bursa <bursa@users.sourceforge.net>
+ */
+
+/** \file
+ * Browser history tree (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_HISTORY_H_
+#define _NETSURF_DESKTOP_HISTORY_H_
+
+#include <stdbool.h>
+
+struct content;
+struct history;
+struct browser_window;
+
+struct history *history_create(void);
+void history_add(struct history *history, struct content *content,
+ char *frag_id);
+void history_update(struct history *history, struct content *content);
+void history_destroy(struct history *history);
+void history_back(struct browser_window *bw, struct history *history);
+void history_forward(struct browser_window *bw, struct history *history);
+bool history_back_available(struct history *history);
+bool history_forward_available(struct history *history);
+void history_size(struct history *history, int *width, int *height);
+bool history_redraw(struct history *history);
+bool history_click(struct browser_window *bw, struct history *history,
+ int x, int y, bool new_window);
+const char *history_position_url(struct history *history, int x, int y);
+
+#endif