2006-03-25 23:30:35 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
|
|
|
|
* Copyright 2005 Richard Wilson <info@tinct.net>
|
2007-08-08 20:16:03 +04:00
|
|
|
*
|
|
|
|
* 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/>.
|
2006-03-25 23:30:35 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
* Browser history tree (implementation).
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
2007-05-31 02:39:54 +04:00
|
|
|
#include "content/content.h"
|
|
|
|
#include "content/urldb.h"
|
|
|
|
#include "css/css.h"
|
|
|
|
#include "desktop/gui.h"
|
|
|
|
#include "desktop/history_core.h"
|
|
|
|
#include "desktop/plotters.h"
|
|
|
|
#include "image/bitmap.h"
|
|
|
|
#include "render/font.h"
|
|
|
|
#include "utils/log.h"
|
|
|
|
#include "utils/url.h"
|
|
|
|
#include "utils/utils.h"
|
2006-03-25 23:30:35 +03:00
|
|
|
|
|
|
|
|
|
|
|
#define WIDTH 100
|
|
|
|
#define HEIGHT 86
|
|
|
|
#define RIGHT_MARGIN 50
|
|
|
|
#define BOTTOM_MARGIN 30
|
|
|
|
|
2006-09-02 19:52:41 +04:00
|
|
|
struct history_page {
|
2007-04-18 06:52:26 +04:00
|
|
|
char *url; /**< Page URL, never 0. */
|
|
|
|
char *frag_id; /** Fragment identifier, or 0. */
|
|
|
|
char *title; /**< Page title, never 0. */
|
2006-09-02 19:52:41 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
/** A node in the history tree. */
|
|
|
|
struct history_entry {
|
|
|
|
struct history_page page;
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2006-04-23 01:35:28 +04:00
|
|
|
static struct history_entry *history_clone_entry(struct history *history,
|
|
|
|
struct history_entry *entry);
|
2006-03-25 23:30:35 +03:00
|
|
|
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,
|
2009-03-09 02:08:27 +03:00
|
|
|
struct history_entry *entry,
|
|
|
|
int x0, int y0, int x1, int y1,
|
|
|
|
int x, int y, bool clip);
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
|
|
|
|
2006-07-04 18:07:07 +04:00
|
|
|
history = calloc(1, sizeof *history);
|
2006-03-25 23:30:35 +03:00
|
|
|
if (!history) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-07-04 18:07:07 +04:00
|
|
|
history->width = RIGHT_MARGIN / 2;
|
|
|
|
history->height = BOTTOM_MARGIN / 2;
|
2006-03-25 23:30:35 +03:00
|
|
|
return history;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-22 20:38:13 +04:00
|
|
|
/**
|
|
|
|
* Clone a history tree
|
|
|
|
*
|
|
|
|
* \param history opaque history structure, as returned by history_create()
|
|
|
|
*
|
|
|
|
* \return pointer to an opaque history structure, 0 on failure.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct history *history_clone(struct history *history)
|
|
|
|
{
|
|
|
|
struct history *new_history;
|
|
|
|
|
|
|
|
if (!history->start)
|
|
|
|
return history_create();
|
|
|
|
|
|
|
|
new_history = malloc(sizeof *history);
|
|
|
|
if (!new_history)
|
|
|
|
return 0;
|
|
|
|
memcpy(new_history, history, sizeof *history);
|
|
|
|
|
2006-04-23 01:35:28 +04:00
|
|
|
new_history->start = history_clone_entry(new_history,
|
|
|
|
new_history->start);
|
|
|
|
if (!history->start) {
|
2007-04-08 00:30:39 +04:00
|
|
|
LOG(("Insufficient memory to clone history"));
|
2006-04-22 20:38:13 +04:00
|
|
|
warn_user("NoMemory", 0);
|
2006-04-22 22:24:18 +04:00
|
|
|
history_destroy(new_history);
|
|
|
|
return 0;
|
2006-04-22 20:38:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return new_history;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clone a history entry
|
|
|
|
*
|
|
|
|
* \param history opaque history structure, as returned by history_create()
|
|
|
|
* \param start entry to clone
|
|
|
|
*
|
2006-04-23 01:35:28 +04:00
|
|
|
* \return a cloned history entry, or 0 on error
|
2006-04-22 20:38:13 +04:00
|
|
|
*/
|
|
|
|
|
2006-04-23 01:35:28 +04:00
|
|
|
struct history_entry *history_clone_entry(struct history *history,
|
|
|
|
struct history_entry *entry)
|
2006-04-22 20:38:13 +04:00
|
|
|
{
|
|
|
|
struct history_entry *child;
|
2006-04-23 01:35:28 +04:00
|
|
|
struct history_entry *new_child;
|
|
|
|
struct history_entry *prev = NULL;
|
2006-04-22 20:38:13 +04:00
|
|
|
struct history_entry *new_entry;
|
|
|
|
|
2007-04-18 06:52:26 +04:00
|
|
|
assert(entry->page.url);
|
|
|
|
assert(entry->page.title);
|
|
|
|
|
2006-04-22 20:38:13 +04:00
|
|
|
/* clone the entry */
|
|
|
|
new_entry = malloc(sizeof *entry);
|
2006-06-29 02:45:48 +04:00
|
|
|
if (!new_entry)
|
2006-04-23 01:35:28 +04:00
|
|
|
return 0;
|
2006-04-22 20:38:13 +04:00
|
|
|
memcpy(new_entry, entry, sizeof *entry);
|
2006-09-02 19:52:41 +04:00
|
|
|
new_entry->page.url = strdup(entry->page.url);
|
|
|
|
if (entry->page.frag_id)
|
|
|
|
new_entry->page.frag_id = strdup(entry->page.frag_id);
|
|
|
|
new_entry->page.title = strdup(entry->page.title);
|
2007-04-18 06:52:26 +04:00
|
|
|
if (!new_entry->page.url || !new_entry->page.title ||
|
2006-09-02 19:52:41 +04:00
|
|
|
((entry->page.frag_id) && (!new_entry->page.frag_id))) {
|
|
|
|
free(new_entry->page.url);
|
|
|
|
free(new_entry->page.title);
|
|
|
|
free(new_entry->page.frag_id);
|
2006-06-29 02:45:48 +04:00
|
|
|
free(new_entry);
|
2006-04-23 01:35:28 +04:00
|
|
|
return 0;
|
2006-04-22 22:24:18 +04:00
|
|
|
}
|
2006-11-27 18:35:18 +03:00
|
|
|
|
2006-04-23 01:35:28 +04:00
|
|
|
/* update references */
|
2006-04-22 20:38:13 +04:00
|
|
|
if (history->current == entry)
|
|
|
|
history->current = new_entry;
|
|
|
|
|
2006-04-23 01:35:28 +04:00
|
|
|
/* recurse for all children */
|
|
|
|
for (child = new_entry->forward; child; child = child->next) {
|
|
|
|
new_child = history_clone_entry(history, child);
|
2006-06-29 02:45:48 +04:00
|
|
|
if (new_child)
|
2007-04-08 00:30:39 +04:00
|
|
|
new_child->back = new_entry;
|
2006-04-23 01:35:28 +04:00
|
|
|
if (prev)
|
|
|
|
prev->next = new_child;
|
|
|
|
if (new_entry->forward == child)
|
|
|
|
new_entry->forward = new_child;
|
|
|
|
if (new_entry->forward_pref == child)
|
|
|
|
new_entry->forward_pref = new_child;
|
|
|
|
if (new_entry->forward_last == child)
|
|
|
|
new_entry->forward_last = new_child;
|
2006-06-29 02:45:48 +04:00
|
|
|
if (!new_child)
|
|
|
|
return 0;
|
2006-04-23 01:35:28 +04:00
|
|
|
prev = new_child;
|
2006-04-22 20:38:13 +04:00
|
|
|
}
|
2006-04-23 01:35:28 +04:00
|
|
|
return new_entry;
|
2006-04-22 20:38:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
/**
|
|
|
|
* 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;
|
2008-04-07 15:15:09 +04:00
|
|
|
struct bitmap *bitmap;
|
2006-03-25 23:30:35 +03:00
|
|
|
|
|
|
|
assert(history);
|
|
|
|
assert(content);
|
|
|
|
|
|
|
|
/* allocate space */
|
|
|
|
entry = malloc(sizeof *entry);
|
2007-04-18 06:52:26 +04:00
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
res = url_normalize(content->url, &url);
|
|
|
|
if (res != URL_FUNC_OK) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
return;
|
|
|
|
}
|
2007-04-07 21:58:42 +04:00
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
title = strdup(content->title ? content->title : url);
|
2007-04-07 21:58:42 +04:00
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
if (!entry || !url || !title) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
free(entry);
|
|
|
|
free(url);
|
|
|
|
free(title);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-09-02 19:52:41 +04:00
|
|
|
entry->page.url = url;
|
|
|
|
entry->page.frag_id = frag_id ? strdup(frag_id) : 0;
|
|
|
|
entry->page.title = title;
|
2006-03-25 23:30:35 +03:00
|
|
|
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 */
|
2006-04-10 03:21:13 +04:00
|
|
|
bitmap = urldb_get_thumbnail(url);
|
2006-03-25 23:30:35 +03:00
|
|
|
if (!bitmap) {
|
|
|
|
bitmap = bitmap_create(WIDTH, HEIGHT,
|
|
|
|
BITMAP_NEW | BITMAP_CLEAR_MEMORY |
|
|
|
|
BITMAP_OPAQUE | BITMAP_PERSISTENT);
|
|
|
|
if (!bitmap) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
return;
|
|
|
|
}
|
2009-02-18 16:25:57 +03:00
|
|
|
if (thumbnail_create(content, bitmap, url) == false) {
|
|
|
|
/* Thumbnailing failed. Ignore it silently */
|
|
|
|
bitmap_destroy(bitmap);
|
|
|
|
bitmap = NULL;
|
|
|
|
}
|
2006-03-25 23:30:35 +03:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2007-04-18 06:52:26 +04:00
|
|
|
char *title;
|
|
|
|
char *url;
|
|
|
|
url_func_result res;
|
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
if (!history || !history->current || !history->current->bitmap)
|
|
|
|
return;
|
|
|
|
|
2007-04-18 06:52:26 +04:00
|
|
|
assert(history->current->page.url);
|
|
|
|
assert(history->current->page.title);
|
|
|
|
|
|
|
|
if (content->title) {
|
|
|
|
title = strdup(content->title);
|
|
|
|
if (!title) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res = url_normalize(content->url, &url);
|
|
|
|
if (res != URL_FUNC_OK) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
title = url;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(title);
|
|
|
|
free(history->current->page.title);
|
|
|
|
history->current->page.title = title;
|
2006-11-27 18:35:18 +03:00
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
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);
|
2006-09-02 19:52:41 +04:00
|
|
|
free(entry->page.url);
|
|
|
|
if (entry->page.frag_id)
|
|
|
|
free(entry->page.frag_id);
|
|
|
|
free(entry->page.title);
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
2006-04-22 22:24:18 +04:00
|
|
|
struct history_entry *current;
|
2006-03-25 23:30:35 +03:00
|
|
|
|
2007-04-08 01:33:54 +04:00
|
|
|
// LOG(("%p %p %p", bw, history, entry));
|
|
|
|
// LOG(("%s %s %s",
|
|
|
|
// entry->page.url, entry->page.title, entry->page.frag_id));
|
2007-04-07 21:58:42 +04:00
|
|
|
|
2006-09-02 19:52:41 +04:00
|
|
|
if (entry->page.frag_id) {
|
2007-04-08 01:33:54 +04:00
|
|
|
url = malloc(strlen(entry->page.url) +
|
|
|
|
strlen(entry->page.frag_id) + 5);
|
2006-03-25 23:30:35 +03:00
|
|
|
if (!url) {
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
return;
|
|
|
|
}
|
2006-09-02 19:52:41 +04:00
|
|
|
sprintf(url, "%s#%s", entry->page.url, entry->page.frag_id);
|
2006-03-25 23:30:35 +03:00
|
|
|
}
|
|
|
|
else
|
2006-09-02 19:52:41 +04:00
|
|
|
url = entry->page.url;
|
2006-03-25 23:30:35 +03:00
|
|
|
|
2006-04-22 22:24:18 +04:00
|
|
|
if (new_window) {
|
|
|
|
current = history->current;
|
|
|
|
history->current = entry;
|
2008-08-24 14:31:38 +04:00
|
|
|
browser_window_create(url, bw, 0, false, false);
|
2006-04-22 22:24:18 +04:00
|
|
|
history->current = current;
|
|
|
|
} else {
|
2006-03-25 23:30:35 +03:00
|
|
|
history->current = entry;
|
2006-04-22 22:24:18 +04:00
|
|
|
browser_window_go(bw, url, 0, false);
|
2006-03-25 23:30:35 +03:00
|
|
|
}
|
|
|
|
|
2006-09-02 19:52:41 +04:00
|
|
|
if (entry->page.frag_id)
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
2006-11-27 18:35:18 +03:00
|
|
|
|
2006-07-05 21:28:30 +04:00
|
|
|
if (!history)
|
|
|
|
return;
|
2006-03-25 23:30:35 +03:00
|
|
|
|
|
|
|
history->width = 0;
|
2006-07-04 18:07:07 +04:00
|
|
|
if (history->start)
|
|
|
|
history->height = history_layout_subtree(history,
|
|
|
|
history->start, RIGHT_MARGIN / 2, BOTTOM_MARGIN / 2,
|
|
|
|
shuffle);
|
|
|
|
else
|
|
|
|
history->height = 0;
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
2006-11-27 18:35:18 +03:00
|
|
|
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
2009-03-09 02:08:27 +03:00
|
|
|
return history_redraw_entry(history, history->start, 0, 0, 0, 0, 0, 0, false);
|
2006-03-25 23:30:35 +03:00
|
|
|
}
|
|
|
|
|
2009-03-09 02:08:27 +03:00
|
|
|
/**
|
|
|
|
* Redraw part of a history.
|
|
|
|
*
|
|
|
|
* \param history history to render
|
|
|
|
* \param x0 left X co-ordinate of redraw area
|
|
|
|
* \param y0 top Y co-ordinate of redraw area
|
|
|
|
* \param x1 right X co-ordinate of redraw area
|
|
|
|
* \param y1 lower Y co-ordinate of redraw area
|
|
|
|
* \param x start X co-ordinate on plot canvas
|
|
|
|
* \param y start Y co-ordinate on plot canvas
|
|
|
|
*
|
|
|
|
* The current plotter is used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool history_redraw_rectangle(struct history *history,
|
|
|
|
int x0, int y0, int x1, int y1,
|
|
|
|
int x, int y)
|
|
|
|
{
|
|
|
|
if (!history->start)
|
|
|
|
return true;
|
|
|
|
return history_redraw_entry(history, history->start,
|
|
|
|
x0, y0, x1, y1, x, y, true);
|
|
|
|
}
|
2006-03-25 23:30:35 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursively redraw a history_entry.
|
|
|
|
*
|
|
|
|
* \param history history containing the entry
|
|
|
|
* \param history_entry entry to render
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool history_redraw_entry(struct history *history,
|
2009-03-09 02:08:27 +03:00
|
|
|
struct history_entry *entry,
|
|
|
|
int x0, int y0, int x1, int y1,
|
|
|
|
int x, int y, bool clip)
|
2006-03-25 23:30:35 +03:00
|
|
|
{
|
|
|
|
size_t char_offset;
|
|
|
|
int actual_x;
|
|
|
|
struct history_entry *child;
|
|
|
|
colour c = entry == history->current ? 0x0000ff : 0x333333;
|
2006-03-27 01:26:47 +04:00
|
|
|
int tailsize = 5;
|
2009-03-09 02:08:27 +03:00
|
|
|
int xoffset = x - x0;
|
|
|
|
int yoffset = y - y0;
|
|
|
|
|
|
|
|
if (clip) {
|
|
|
|
if(!plot.clip(x0 + xoffset, y0 + yoffset, x1 + xoffset, y1 + yoffset))
|
|
|
|
return false;
|
|
|
|
}
|
2006-11-27 18:35:18 +03:00
|
|
|
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!plot.bitmap(entry->x + xoffset, entry->y + yoffset, WIDTH, HEIGHT,
|
2009-06-30 17:02:23 +04:00
|
|
|
entry->bitmap, 0xffffff, 0))
|
2006-03-25 23:30:35 +03:00
|
|
|
return false;
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!plot.rectangle(entry->x - 1 + xoffset, entry->y - 1 + yoffset,
|
|
|
|
WIDTH + 1, HEIGHT + 1,
|
2006-03-25 23:30:35 +03:00
|
|
|
entry == history->current ? 2 : 1, c, false, false))
|
|
|
|
return false;
|
|
|
|
|
First merge of Adam Blokus' GSoC work from his branch 'branches/adamblokus/netsurf'.
Merged revisions 4212-4552,4554-4709,4711-4724 via svnmerge from
svn://svn.netsurf-browser.org/branches/adamblokus/netsurf
........
r4212 | adamblokus | 2008-05-26 19:42:31 +0200 (Mon, 26 May 2008) | 4 lines
Pdf plotting skeleton pinned on Print Preview in GTK.
Just creates a file and draws lines.
........
r4213 | adamblokus | 2008-05-27 00:11:03 +0200 (Tue, 27 May 2008) | 4 lines
Pdf plotter - added drawing some graphic primitives.
Still with limited functionality, but a snapshot of the
currently viewed page can be made and resembles the original.
........
r4214 | adamblokus | 2008-05-27 11:43:31 +0200 (Tue, 27 May 2008) | 2 lines
Corrected encoding name
........
r4215 | adamblokus | 2008-05-27 12:47:26 +0200 (Tue, 27 May 2008) | 3 lines
Colours and polygons added.
........
r4217 | adamblokus | 2008-05-27 21:39:35 +0200 (Tue, 27 May 2008) | 6 lines
Added rectangles, filled boxes and clipping.
Taken into consideration joty's comments.
Added a todo list for this part.
Added some debug stuff and checking boundaries.
........
r4218 | adamblokus | 2008-05-28 12:37:30 +0200 (Wed, 28 May 2008) | 2 lines
Added path ploting (not sure if valid argument order for bezier) and dashed/dotted line styles
........
r4221 | adamblokus | 2008-05-28 22:11:05 +0200 (Wed, 28 May 2008) | 3 lines
Some more options in graphic primitives and normalizing some parameters.
........
r4235 | adamblokus | 2008-05-31 22:54:56 +0200 (Sat, 31 May 2008) | 4 lines
Plotting changed as jmb suggested (is the least invasive one from the possible)
Added dummy bitmap plotting - way of plotting an image is determined by its type.
........
r4251 | adamblokus | 2008-06-03 17:12:15 +0200 (Tue, 03 Jun 2008) | 3 lines
Added plotting jpg and png images - quite a lot to improve in this code, but it seems to work ;)
........
r4263 | adamblokus | 2008-06-05 14:20:32 +0200 (Thu, 05 Jun 2008) | 3 lines
Added hadling images other than png and jpeg - with transparency.
........
r4267 | adamblokus | 2008-06-06 15:36:34 +0200 (Fri, 06 Jun 2008) | 5 lines
Added handling NULL-returns from all mallocs.
Added plot_bitmap_tile handling.
Changed code style a little.
........
r4327 | adamblokus | 2008-06-12 17:46:34 +0200 (Thu, 12 Jun 2008) | 5 lines
Added a first prototype of the paged-output organization.
Still not sure about naming, file locations etc.
Works with the same pdf plotting as before.
........
r4328 | adamblokus | 2008-06-13 13:52:15 +0200 (Fri, 13 Jun 2008) | 4 lines
Added primitive width adjustment and outputing the whole
website in multiple pages.
........
r4336 | joty | 2008-06-15 15:06:57 +0200 (Sun, 15 Jun 2008) | 1 line
Fix RISC OS build failure (change r4235 wasn't complete).
........
r4337 | joty | 2008-06-15 18:15:32 +0200 (Sun, 15 Jun 2008) | 16 lines
This enables "Export PDF" in RISC OS build:
- Docs/Doxyfile(PREDEFINED): Added WITH_PDF_EXPORT
- Makefile.sources(S_PDF): Add to RISC OS target as well.
- utils/config.h: Define WITH_PDF_EXPORT which controls if we want to have
PDF export functionality or not.
- riscos/save_pdf.c,riscos/save_pdf.h(save_as_pdf): Use PDF print API made
by Adam Blokus to write a PDF file under RISC OS.
- riscos/save.c: Call save_as_pdf added.
- riscos/menus.c: Add 'Export->PDF' menu entry.
- riscos/menus.h(menu_action): Added BROWSER_EXPORT_PDF.
- desktop/gui.h(gui_save_type): Added GUI_SAVE_PDF.
- desktop/print.c(print_run): Added return value.
- Makefile(CCACHE): Moved closed to the place where CC is set for the first time.
(LDFLAGS): Centralised adding all non-pkgconfig libraries and added Haru + PNG libs.
........
r4343 | adamblokus | 2008-06-16 01:08:52 +0200 (Mon, 16 Jun 2008) | 3 lines
Added margins and page size adjustment.
........
r4412 | adamblokus | 2008-06-21 20:22:07 +0200 (Sat, 21 Jun 2008) | 4 lines
Added 'fuzzy' margins on page bottom.
Disabled direct png embedding, because it is too unstable in Haru now.
........
r4421 | adamblokus | 2008-06-22 18:52:28 +0200 (Sun, 22 Jun 2008) | 2 lines
Added "Save as.." dialog and Export->PDF menu entry. Print preview still works with default path.
........
r4437 | adamblokus | 2008-06-25 02:44:46 +0200 (Wed, 25 Jun 2008) | 4 lines
Added skeleton of applying loose layout.
Minor code cleaning-up.
........
r4492 | adamblokus | 2008-07-02 09:02:42 +0200 (Wed, 02 Jul 2008) | 5 lines
Implemented the elementar ideas of the loose layout.
Added scaling in the printing routine.
Added some basic demonstrations.
........
r4493 | adamblokus | 2008-07-02 09:05:55 +0200 (Wed, 02 Jul 2008) | 3 lines
Cleaned up the loosing code - commited to much of leftover rubbish code.
........
r4507 | adamblokus | 2008-07-04 14:25:48 +0200 (Fri, 04 Jul 2008) | 4 lines
Added duplicating box tree and current content - window flickering during printing solved.
Minor error checking after new HPDF_Image_AddSMask call.
........
r4515 | adamblokus | 2008-07-06 22:28:16 +0200 (Sun, 06 Jul 2008) | 2 lines
Changes in loosen layout (image resizing).
........
r4517 | adamblokus | 2008-07-06 22:38:23 +0200 (Sun, 06 Jul 2008) | 2 lines
Added pdf font handling and rendering functions with the use of Haru functions.
........
r4555 | adamblokus | 2008-07-10 00:59:05 +0200 (Thu, 10 Jul 2008) | 2 lines
Added a very basic and still buggy GTK print implementation.
........
r4565 | adamblokus | 2008-07-10 14:50:16 +0200 (Thu, 10 Jul 2008) | 2 lines
Added gtk printing one more time - I have forgotten to add the main file.
........
r4566 | adamblokus | 2008-07-10 14:57:02 +0200 (Thu, 10 Jul 2008) | 2 lines
removed error with comment
........
r4569 | adamblokus | 2008-07-10 15:52:55 +0200 (Thu, 10 Jul 2008) | 5 lines
Major style improvements - added a lot of doxygen comments,
followed tlsa's style guide.
Added some more error checking, too.
........
r4575 | adamblokus | 2008-07-10 18:48:26 +0200 (Thu, 10 Jul 2008) | 2 lines
Cleaned up the code.
........
r4687 | adamblokus | 2008-07-17 14:17:19 +0200 (Thu, 17 Jul 2008) | 2 lines
Changed everything according to jmb's review plus some minor bug fixes to gtk_print.
........
r4688 | adamblokus | 2008-07-17 17:16:34 +0200 (Thu, 17 Jul 2008) | 2 lines
Solved the netsurf.glade clash from r4421.
........
r4693 | adamblokus | 2008-07-18 18:11:51 +0200 (Fri, 18 Jul 2008) | 2 lines
Fixed bug with wrong number of pages in gtk printing.
........
r4695 | adamblokus | 2008-07-18 19:59:24 +0200 (Fri, 18 Jul 2008) | 3 lines
- fixed uncommented line from the previous commit
- fixed bug with scale bigger than 1.0 (incorretly clipped page)
........
r4696 | adamblokus | 2008-07-18 23:28:00 +0200 (Fri, 18 Jul 2008) | 2 lines
Fixed bug in gtk_print_font_paint (and nsfont_paint).
........
r4697 | adamblokus | 2008-07-18 23:35:38 +0200 (Fri, 18 Jul 2008) | 2 lines
Bug fix in nsfont_paint.
........
r4711 | adamblokus | 2008-07-19 22:44:15 +0200 (Sat, 19 Jul 2008) | 2 lines
Added gtk_selection files.
........
r4712 | adamblokus | 2008-07-20 11:15:06 +0200 (Sun, 20 Jul 2008) | 2 lines
Addam missing glade files.
........
r4713 | joty | 2008-07-20 17:13:10 +0200 (Sun, 20 Jul 2008) | 1 line
Follow change r4517 for RISC OS and BeOS platforms : Added pdf font handling and rendering functions with the use of Haru functions.
........
r4714 | joty | 2008-07-20 18:19:50 +0200 (Sun, 20 Jul 2008) | 1 line
Declare haru_nsfont iso define an instance for each C source including the font_haru.h header. This fixes breakage of PDF export on RISC OS.
........
r4724 | adamblokus | 2008-07-23 03:30:08 +0200 (Wed, 23 Jul 2008) | 6 lines
Applied changes according to joty's review.
Added checking the dimensions of a plotted image to pdf plotter.
Commented out jpg embedding (it seems to cause some problems
I'll bring it back when I figure out what's wrong) .
Added back some files removed by mistake.
........
svn path=/trunk/netsurf/; revision=4741
2008-07-26 20:01:59 +04:00
|
|
|
if (!nsfont.font_position_in_string(&css_base_style, entry->page.title,
|
2007-04-18 06:52:26 +04:00
|
|
|
strlen(entry->page.title), WIDTH,
|
|
|
|
&char_offset, &actual_x))
|
2006-03-25 23:30:35 +03:00
|
|
|
return false;
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!plot.text(entry->x + xoffset, entry->y + HEIGHT + 12 + yoffset,
|
|
|
|
&css_base_style, entry->page.title, char_offset, 0xffffff, c))
|
2006-03-25 23:30:35 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
for (child = entry->forward; child; child = child->next) {
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!plot.line(entry->x + WIDTH + xoffset,
|
|
|
|
entry->y + HEIGHT / 2 + yoffset,
|
|
|
|
entry->x + WIDTH + tailsize + xoffset,
|
|
|
|
entry->y + HEIGHT / 2 + yoffset, 1,
|
2006-03-27 01:26:47 +04:00
|
|
|
0x333333, false, false))
|
|
|
|
return false;
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!plot.line(entry->x + WIDTH + tailsize + xoffset,
|
|
|
|
entry->y + HEIGHT / 2 + yoffset,
|
|
|
|
child->x - tailsize +xoffset,
|
|
|
|
child->y + HEIGHT / 2 + yoffset, 1,
|
2006-03-27 01:26:47 +04:00
|
|
|
0x333333, false, false))
|
|
|
|
return false;
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!plot.line(child->x - tailsize + xoffset,
|
|
|
|
child->y + HEIGHT / 2 + yoffset,
|
|
|
|
child->x + xoffset, child->y + HEIGHT / 2 + yoffset, 1,
|
2006-03-25 23:30:35 +03:00
|
|
|
0x333333, false, false))
|
|
|
|
return false;
|
2009-03-09 02:08:27 +03:00
|
|
|
if (!history_redraw_entry(history, child, x0, y0, x1, y1, x, y, clip))
|
2006-03-25 23:30:35 +03:00
|
|
|
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;
|
|
|
|
|
2006-09-02 19:52:41 +04:00
|
|
|
return entry->page.url;
|
2006-03-25 23:30:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
2006-11-27 18:35:18 +03:00
|
|
|
|
2006-07-05 21:28:30 +04:00
|
|
|
if (!entry)
|
|
|
|
return 0;
|
2006-03-25 23:30:35 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|