summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/url_store.c89
-rw-r--r--content/url_store.h7
-rw-r--r--debug/debug_bitmap.c9
-rw-r--r--desktop/tree.c31
-rw-r--r--desktop/tree.h2
-rw-r--r--gtk/gtk_bitmap.c9
-rw-r--r--image/bitmap.h1
-rw-r--r--image/gif.c4
-rw-r--r--image/gifread.c4
-rw-r--r--image/jpeg.c1
-rw-r--r--image/mng.c4
-rw-r--r--render/html.c5
-rw-r--r--riscos/bitmap.c579
-rw-r--r--riscos/bitmap.h31
-rw-r--r--riscos/global_history.c32
15 files changed, 746 insertions, 62 deletions
diff --git a/content/url_store.c b/content/url_store.c
index 3c2f6022f..61dd29afd 100644
--- a/content/url_store.c
+++ b/content/url_store.c
@@ -15,6 +15,9 @@
#include <stdlib.h>
#include <string.h>
#include "netsurf/content/url_store.h"
+#ifdef riscos
+#include "netsurf/riscos/bitmap.h"
+#endif
#include "netsurf/utils/url.h"
#include "netsurf/utils/log.h"
@@ -57,8 +60,11 @@ static struct hostname_data *url_store_find_hostname(const char *url) {
assert(url);
res = url_host(url, &hostname);
- if (res != URL_FUNC_OK)
- return NULL;
+ if (res != URL_FUNC_OK) {
+ hostname = strdup("file:/"); /* for 'file:/' */
+ if (!hostname)
+ return NULL;
+ }
hostname_length = strlen(hostname);
/* try to find a matching hostname fairly quickly */
@@ -237,8 +243,11 @@ static struct hostname_data *url_store_match_hostname(const char *url,
assert(url);
res = url_host(url, &hostname);
- if (res != URL_FUNC_OK)
- return NULL;
+ if (res != URL_FUNC_OK) {
+ hostname = strdup("file:/"); /* for 'file:/' */
+ if (!hostname)
+ return NULL;
+ }
hostname_length = strlen(hostname);
www_test = strncmp(hostname, "www.", 4);
@@ -403,6 +412,7 @@ void url_store_load(const char *file) {
int urls;
int i;
int version;
+ int width, height, size;
FILE *fp;
fp = fopen(file, "r");
@@ -414,7 +424,7 @@ void url_store_load(const char *file) {
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
return;
version = atoi(s);
- if ((version != 100) && (version != 101))
+ if ((version < 100) || (version > 102))
return;
@@ -433,7 +443,8 @@ void url_store_load(const char *file) {
break;
url->requests = atoi(s);
}
- } else if (version == 101) {
+ } else if (version >= 101) {
+ /* version 102 is as 101, but with thumbnail information */
/* version 101 is as 100, but in hostname chunks, pre-sorted
* in reverse alphabetical order */
while (fgets(s, MAXIMUM_URL_LENGTH, fp)) {
@@ -472,6 +483,22 @@ void url_store_load(const char *file) {
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
result->data.requests = atoi(s);
+ if (version == 102) {
+ if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
+ break;
+ size = atoi(s);
+ width = size & 65535;
+ height = size >> 16;
+ if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
+ break;
+#ifdef riscos
+ if (s[strlen(s) - 1] == '\n')
+ s[strlen(s) - 1] = '\0';
+ result->data.thumbnail =
+ bitmap_create_file(
+ width, height, s);
+#endif
+ }
}
}
}
@@ -489,7 +516,10 @@ void url_store_save(const char *file) {
struct url_data *url;
int url_count;
char *normal = NULL;
+ const char *thumb_file = "";
+ int thumb_size = 0;
FILE *fp;
+ struct bitmap *bitmap;
fp = fopen(file, "w");
if (!fp) {
@@ -498,13 +528,13 @@ void url_store_save(const char *file) {
}
/* file format version number */
- fprintf(fp, "101\n");
+ fprintf(fp, "102\n");
for (search = url_store_hostnames; search && search->next;
search = search->next);
for (; search; search = search->previous) {
url_count = 0;
for (url = search->url; url; url = url->next)
- if ((url->data.requests > 0) &&
+ if ((url->data.visits > 0) &&
(strlen(url->data.url) <
MAXIMUM_URL_LENGTH))
url_count++;
@@ -514,13 +544,27 @@ void url_store_save(const char *file) {
fprintf(fp, "%s\n%i\n", normal, url_count);
for (url = search->url; url->next; url = url->next);
for (; url; url = url->previous)
- if ((url->data.requests > 0) &&
+ if ((url->data.visits > 0) &&
(strlen(url->data.url) <
- MAXIMUM_URL_LENGTH))
- fprintf(fp, "%s\n%i\n%i\n",
+ MAXIMUM_URL_LENGTH)) {
+#ifdef riscos
+ bitmap = url->data.thumbnail;
+ if (bitmap) {
+ thumb_size = bitmap->width |
+ (bitmap->height << 16);
+ thumb_file = bitmap->filename;
+ } else {
+ thumb_size = 0;
+ thumb_file = "";
+ }
+#endif
+ fprintf(fp, "%s\n%i\n%i\n%i\n%s\n",
url->data.url,
url->data.visits,
- url->data.requests);
+ url->data.requests,
+ thumb_size,
+ thumb_file);
+ }
}
}
fclose(fp);
@@ -547,3 +591,24 @@ void url_store_dump(void) {
}
fprintf(stderr, "\nEnd of hostname data.\n\n");
}
+
+
+void url_store_add_thumbnail(const char *url, struct bitmap *bitmap) {
+ struct url_content *content;
+
+ content = url_store_find(url);
+ if (content) {
+ if (content->thumbnail)
+ bitmap_destroy(content->thumbnail);
+ content->thumbnail = bitmap;
+ }
+}
+
+struct bitmap *url_store_get_thumbnail(const char *url) {
+ struct url_content *content;
+
+ content = url_store_find(url);
+ if (content)
+ return content->thumbnail;
+ return NULL;
+}
diff --git a/content/url_store.h b/content/url_store.h
index 6a101cfe8..412aef438 100644
--- a/content/url_store.h
+++ b/content/url_store.h
@@ -12,7 +12,11 @@
#ifndef _NETSURF_CONTENT_URLSTORE_H_
#define _NETSURF_CONTENT_URLSTORE_H_
+#include "netsurf/image/bitmap.h"
+
+
struct url_content {
+ struct bitmap *thumbnail; /** Thumbnail, or NULL */
char *url; /** URL (including hostname) */
int url_length; /** Length of URL (including hostname) */
int visits; /** Number of times visited */
@@ -31,6 +35,9 @@ struct url_content *url_store_find(const char *url);
char *url_store_match(const char *url, struct url_data **reference);
char *url_store_match_string(const char *text);
+void url_store_add_thumbnail(const char *url, struct bitmap *bitmap);
+struct bitmap *url_store_get_thumbnail(const char *url);
+
void url_store_load(const char *file);
void url_store_save(const char *file);
diff --git a/debug/debug_bitmap.c b/debug/debug_bitmap.c
index bd724e0a0..394a7961f 100644
--- a/debug/debug_bitmap.c
+++ b/debug/debug_bitmap.c
@@ -111,3 +111,12 @@ bool bitmap_save(struct bitmap *bitmap, const char *path)
{
return true;
}
+
+
+/**
+ * The bitmap image has changed, so flush any persistant cache.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+void bitmap_modified(struct bitmap *bitmap) {
+}
diff --git a/desktop/tree.c b/desktop/tree.c
index cc25405f4..df3cb92ca 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -99,10 +99,8 @@ void tree_handle_node_changed(struct tree *tree, struct node *node,
width = node->box.width;
height = node->box.height;
- if (recalculate_sizes)
+ if ((recalculate_sizes) || (expansion))
tree_recalculate_node(node, true);
- else if (expansion)
- tree_recalculate_node(node, false);
if ((node->box.height != height) || (expansion)) {
tree_recalculate_node_positions(tree->root);
tree_redraw_area(tree, 0, node->box.y, 16384, 16384);
@@ -172,6 +170,9 @@ void tree_recalculate_node(struct node *node, bool recalculate_sizes) {
}
} else {
if (recalculate_sizes)
+ for (element = &node->data; element; element = element->next)
+ tree_recalculate_node_element(element);
+ else
tree_recalculate_node_element(&node->data);
node->box.width = node->data.box.width;
node->box.height = node->data.box.height;
@@ -332,7 +333,10 @@ bool tree_handle_expansion(struct tree *tree, struct node *node, bool expanded,
node->expanded = expanded;
if (node->child)
tree_set_node_expanded(node->child, false);
- tree_recalculate_node(node, false);
+ if ((node->data.next) && (node->data.next->box.height == 0))
+ tree_recalculate_node(node, true);
+ else
+ tree_recalculate_node(node, false);
redraw = true;
}
if ((node->child) && (node->expanded))
@@ -993,7 +997,7 @@ struct node *tree_create_URL_node(struct node *parent, const char *title,
if (element) {
element->user_data = filetype;
element->type = NODE_ELEMENT_TEXT;
- element->text = squash_whitespace(url);
+ element->text = strdup(url);
}
element = tree_create_node_element(node, TREE_ELEMENT_ADDED);
if (element) {
@@ -1010,12 +1014,12 @@ struct node *tree_create_URL_node(struct node *parent, const char *title,
element->type = NODE_ELEMENT_TEXT;
element->user_data = visits;
}
+ element = tree_create_node_element(node, TREE_ELEMENT_THUMBNAIL);
+ if (element)
+ element->type = NODE_ELEMENT_THUMBNAIL;
tree_update_URL_node(node);
-
- node->expanded = true;
- tree_recalculate_node(node, true);
- node->expanded = false;
+ tree_recalculate_node(node, false);
return node;
}
@@ -1056,12 +1060,13 @@ struct node *tree_create_URL_node_brief(struct node *parent, const char *title,
element->type = NODE_ELEMENT_TEXT;
element->user_data = visit_date;
}
+ element = tree_create_node_element(node, TREE_ELEMENT_THUMBNAIL);
+ if (element) {
+ element->type = NODE_ELEMENT_THUMBNAIL;
+ }
tree_update_URL_node(node);
-
- node->expanded = true;
- tree_recalculate_node(node, true);
- node->expanded = false;
+ tree_recalculate_node(node, false);
return node;
}
diff --git a/desktop/tree.h b/desktop/tree.h
index 68d97f96d..9f0749b5d 100644
--- a/desktop/tree.h
+++ b/desktop/tree.h
@@ -19,6 +19,7 @@
#define TREE_ELEMENT_LAST_VISIT 3
#define TREE_ELEMENT_VISITS 4
#define TREE_ELEMENT_VISITED 5
+#define TREE_ELEMENT_THUMBNAIL 6
#define NODE_INSTEP 40
@@ -29,6 +30,7 @@ typedef enum {
NODE_ELEMENT_TEXT, /* <-- Text only */
NODE_ELEMENT_TEXT_PLUS_SPRITE, /* <-- Text and sprite */
NODE_ELEMENT_SPRITE, /* <-- Sprite only */
+ NODE_ELEMENT_THUMBNAIL, /* <-- Bitmap only */
} node_element_type;
diff --git a/gtk/gtk_bitmap.c b/gtk/gtk_bitmap.c
index f1c184a4f..788d9c6cf 100644
--- a/gtk/gtk_bitmap.c
+++ b/gtk/gtk_bitmap.c
@@ -140,3 +140,12 @@ bool bitmap_save(struct bitmap *bitmap, const char *path)
{
return true;
}
+
+
+/**
+ * The bitmap image has changed, so flush any persistant cache.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+void bitmap_modified(struct bitmap *bitmap) {
+}
diff --git a/image/bitmap.h b/image/bitmap.h
index 1e68761b3..8c33b8100 100644
--- a/image/bitmap.h
+++ b/image/bitmap.h
@@ -33,5 +33,6 @@ char *bitmap_get_buffer(struct bitmap *bitmap);
size_t bitmap_get_rowstride(struct bitmap *bitmap);
void bitmap_destroy(struct bitmap *bitmap);
bool bitmap_save(struct bitmap *bitmap, const char *path);
+void bitmap_modified(struct bitmap *bitmap);
#endif
diff --git a/image/gif.c b/image/gif.c
index ca77e2b36..4b7fd27ba 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -106,6 +106,8 @@ bool nsgif_convert(struct content *c, int iwidth, int iheight) {
a plot we get some sensible data
*/
gif_decode_frame(c->data.gif.gif, 0);
+ if (c->data.gif.gif->frame_image)
+ bitmap_modified(c->data.gif.gif->frame_image);
/* Schedule the animation if we have one
*/
@@ -158,10 +160,8 @@ void nsgif_get_frame(struct content *c) {
previous_frame = 0;
else
previous_frame = c->data.gif.gif->decoded_frame + 1;
-
for (frame = previous_frame; frame <= current_frame; frame++)
gif_decode_frame(c->data.gif.gif, frame);
-
}
diff --git a/image/gifread.c b/image/gifread.c
index 80ea97d24..4e38fc989 100644
--- a/image/gifread.c
+++ b/image/gifread.c
@@ -802,6 +802,7 @@ gif_decode_frame_exit:
gif->frames[frame].virgin = false;
}
bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque);
+ bitmap_modified(gif->frame_image);
/* Restore the buffer position
*/
@@ -828,7 +829,8 @@ static unsigned int gif_interlaced_line(int height, int y) {
void gif_finalise(struct gif_animation *gif) {
/* Release all our memory blocks
*/
- free(gif->frame_image);
+ if (gif->frame_image)
+ bitmap_destroy(gif->frame_image);
gif->frame_image = NULL;
free(gif->frames);
gif->frames = NULL;
diff --git a/image/jpeg.c b/image/jpeg.c
index 0482aa912..672571f2c 100644
--- a/image/jpeg.c
+++ b/image/jpeg.c
@@ -126,6 +126,7 @@ bool nsjpeg_convert(struct content *c, int w, int h)
}
#endif
} while (cinfo.output_scanline != cinfo.output_height);
+ bitmap_modified(bitmap);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
diff --git a/image/mng.c b/image/mng.c
index fadd6a3af..1c987fa4d 100644
--- a/image/mng.c
+++ b/image/mng.c
@@ -293,13 +293,13 @@ bool nsmng_convert(struct content *c, int width, int height) {
LOG(("Unable to start display (%i)", status));
return nsmng_broadcast_error(c);
}
+ bitmap_modified(c->bitmap);
/* Optimise the plotting of JNG/PNGs
*/
c->data.mng.opaque_test_pending = (c->type == CONTENT_PNG) || (c->type == CONTENT_JNG);
if (c->data.mng.opaque_test_pending)
bitmap_set_opaque(c->bitmap, false);
-
return true;
}
@@ -467,6 +467,8 @@ void nsmng_animate(void *p) {
c->data.mng.waiting = false;
mng_display_resume(c->data.mng.handle);
c->data.mng.opaque_test_pending = true;
+ if (c->bitmap)
+ bitmap_modified(c->bitmap);
}
}
diff --git a/render/html.c b/render/html.c
index 0c350342f..fe3488709 100644
--- a/render/html.c
+++ b/render/html.c
@@ -1143,6 +1143,11 @@ void html_destroy(struct content *c)
imagemap_destroy(c);
+ if (c->bitmap) {
+ bitmap_destroy(c->bitmap);
+ c->bitmap = NULL;
+ }
+
if (c->data.html.parser)
htmlFreeParserCtxt(c->data.html.parser);
diff --git a/riscos/bitmap.c b/riscos/bitmap.c
index 2f2416550..a29cc1229 100644
--- a/riscos/bitmap.c
+++ b/riscos/bitmap.c
@@ -1,8 +1,9 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
- * http://www.opensource.org/licenses/gpl-license
+ * http://www.opensource.org/licenses/gpl-license
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2005 Richard Wilson <info@tinct.net>
*/
/** \file
@@ -15,14 +16,136 @@
#include <assert.h>
#include <stdbool.h>
#include <string.h>
+#include <swis.h>
+#include "oslib/osfile.h"
#include "oslib/osspriteop.h"
#include "netsurf/content/content.h"
#include "netsurf/image/bitmap.h"
#include "netsurf/riscos/bitmap.h"
+#include "netsurf/riscos/filename.h"
#include "netsurf/riscos/image.h"
+#include "netsurf/riscos/options.h"
+#include "netsurf/riscos/tinct.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/utils.h"
+#define MAINTENANCE_THRESHOLD 32
+
+/** The head of the bitmap list
+*/
+struct bitmap *bitmap_head = NULL;
+
+/** Whether maintenance of the pool states is needed
+*/
+bool bitmap_maintenance = false;
+
+/** Whether maintenance of the pool is high priority
+*/
+bool bitmap_maintenance_priority = false;
+
+/** Maximum amount of memory for direct images
+*/
+unsigned int bitmap_direct_size;
+
+/** Current amount of memory for direct images
+*/
+unsigned int bitmap_direct_used = 0;
+
+/** Total size of compressed area
+*/
+unsigned int bitmap_compressed_size;
+
+/** Total size of compressed area
+*/
+unsigned int bitmap_compressed_used = 0;
+
+
+/** Compressed data header
+*/
+struct bitmap_compressed_header {
+ int width;
+ int height;
+ char name[12];
+ unsigned int flags;
+ unsigned int input_size;
+};
+
+char bitmap_filename[256];
+
+
+bool bitmap_initialise(struct bitmap *bitmap, bool clear);
+void bitmap_decompress(struct bitmap *bitmap);
+void bitmap_compress(struct bitmap *bitmap);
+void bitmap_load_file(struct bitmap *bitmap);
+void bitmap_save_file(struct bitmap *bitmap);
+void bitmap_delete_file(struct bitmap *bitmap);
+
+
+/**
+ * Initialise the bitmap memory pool.
+ */
+
+void bitmap_initialise_memory(void)
+{
+ int available_memory, direct_size, compressed_size;
+ int next_slot, free_slot;
+ os_error *error;
+
+ /* calculate how much memory is currently free */
+ error = xwimp_slot_size(-1, -1, 0, &next_slot, &free_slot);
+ if (error) {
+ LOG(("xwimp_slot_size: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
+ available_memory = next_slot + free_slot;
+
+ /* calculate our memory block sizes */
+ if (option_image_memory_direct == -1) {
+ /* claim 20% of free memory - min 256KB, max 32768KB */
+ direct_size = available_memory * 0.20;
+ if (direct_size < (256 << 10))
+ direct_size = (256 << 10);
+ if (direct_size > (32768 << 10))
+ direct_size = (32768 << 10);
+ } else {
+ direct_size = (option_image_memory_direct << 10);
+ }
+ if (option_image_memory_compressed == -1) {
+ /* claim 5% of free memory - min 256KB, max 4192KB */
+ compressed_size = available_memory * 0.05;
+ if (compressed_size < (256 << 10))
+ compressed_size = 0;
+ if (compressed_size > (4192 << 10))
+ compressed_size = (4192 << 10);
+ } else {
+ compressed_size = (option_image_memory_compressed << 10);
+ }
+
+ /* set our values. No fixed buffers here, ho hum. */
+ bitmap_direct_size = direct_size;
+ bitmap_compressed_size = compressed_size;
+ LOG(("Allowing %iKB of memory for compressed images.",
+ (bitmap_compressed_size >> 10)));
+ LOG(("Allowing %iKB of memory for uncompressed images.",
+ (bitmap_direct_size >> 10)));
+}
+
+
+/**
+ * Prepare for the end of a session.
+ */
+
+void bitmap_quit(void)
+{
+ struct bitmap *bitmap;
+
+ for (bitmap = bitmap_head; bitmap; bitmap = bitmap->next)
+ if ((bitmap->persistent) && (bitmap->filename[0] == '\0'))
+ bitmap_save_file(bitmap);
+}
+
/**
* Create a bitmap.
@@ -35,28 +158,100 @@
struct bitmap *bitmap_create(int width, int height, bool clear)
{
- unsigned int area_size;
struct bitmap *bitmap;
- osspriteop_area *sprite_area;
- osspriteop_header *sprite;
if (width == 0 || height == 0)
return NULL;
- area_size = 16 + 44 + width * height * 4;
- if (clear)
- bitmap = calloc(sizeof(struct bitmap) + area_size, 1);
- else
- bitmap = malloc(sizeof(struct bitmap) + area_size);
+ bitmap = calloc(sizeof(struct bitmap), 1);
if (!bitmap)
return NULL;
-
bitmap->width = width;
bitmap->height = height;
bitmap->opaque = false;
+ if (!bitmap_initialise(bitmap, clear)) {
+ free(bitmap);
+ return NULL;
+ }
+
+ /* link into our list of bitmaps at the head */
+ bitmap_maintenance = true;
+ bitmap_maintenance_priority |=
+ (bitmap_direct_used > bitmap_direct_size * 1.1);
+ if (bitmap_head) {
+ bitmap->next = bitmap_head;
+ bitmap_head->previous = bitmap;
+ }
+ bitmap_head = bitmap;
+ return bitmap;
+}
+
+
+/**
+ * Create a persistent, opaque bitmap from a file reference.
+ *
+ * \param width width of image in pixels
+ * \param height width of image in pixels
+ * \param file the file containing the image data
+ * \return an opaque struct bitmap, or NULL on memory exhaustion
+ */
+
+struct bitmap *bitmap_create_file(int width, int height, char *file)
+{
+ struct bitmap *bitmap;
+ struct bitmap *link;
+
+ if (width == 0 || height == 0)
+ return NULL;
+
+ if (!ro_filename_claim(file))
+ return NULL;
+ bitmap = calloc(sizeof(struct bitmap), 1);
+ if (!bitmap)
+ return NULL;
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->opaque = true;
+ bitmap->persistent = true;
+ sprintf(bitmap->filename, file);
+
+ /* link into our list of bitmaps at the tail */
+ if (bitmap_head) {
+ for (link = bitmap_head; link->next; link = link->next);
+ link->next = bitmap;
+ bitmap->previous = link;
+ } else {
+ bitmap_head = bitmap;
+ }
+ return bitmap;
+}
+
+
+/**
+ * Initialise a bitmaps sprite area.
+ *
+ * \param bitmap the bitmap to initialise
+ * \param clear whether to clear the image ready for use
+ */
+
+bool bitmap_initialise(struct bitmap *bitmap, bool clear)
+{
+ unsigned int area_size;
+ osspriteop_area *sprite_area;
+ osspriteop_header *sprite;
+
+ area_size = 16 + 44 + bitmap->width * bitmap->height * 4;
+ if (clear)
+ bitmap->sprite_area = calloc(area_size, 1);
+ else
+ bitmap->sprite_area = malloc(area_size);
+ if (!bitmap->sprite_area) {
+ return false;
+ }
+ bitmap_direct_used += area_size;
/* area control block */
- sprite_area = &bitmap->sprite_area;
+ sprite_area = bitmap->sprite_area;
sprite_area->size = area_size;
sprite_area->sprite_count = 1;
sprite_area->first = 16;
@@ -68,14 +263,13 @@ struct bitmap *bitmap_create(int width, int height, bool clear)
if (!clear)
memset(sprite->name, 0x00, 12);
strncpy(sprite->name, "bitmap", 12);
- sprite->width = width - 1;
- sprite->height = height - 1;
+ sprite->width = bitmap->width - 1;
+ sprite->height = bitmap->height - 1;
sprite->left_bit = 0;
sprite->right_bit = 31;
sprite->image = sprite->mask = 44;
- sprite->mode = (os_mode) 0x301680b5;
-
- return bitmap;
+ sprite->mode = tinct_SPRITE_MODE;
+ return true;
}
@@ -102,9 +296,11 @@ bool bitmap_test_opaque(struct bitmap *bitmap)
{
assert(bitmap);
char *sprite = bitmap_get_buffer(bitmap);
+ if (!sprite)
+ return false;
unsigned int width = bitmap_get_rowstride(bitmap);
osspriteop_header *sprite_header =
- (osspriteop_header *) (&(bitmap->sprite_area) + 1);
+ (osspriteop_header *) (bitmap->sprite_area + 1);
unsigned int height = (sprite_header->height + 1);
unsigned int size = width * height;
unsigned *p = (unsigned*)sprite;
@@ -153,7 +349,36 @@ bool bitmap_get_opaque(struct bitmap *bitmap)
char *bitmap_get_buffer(struct bitmap *bitmap)
{
assert(bitmap);
- return ((char *) (&(bitmap->sprite_area))) + 16 + 44;
+
+ /* move to the head of the list */
+ if (bitmap_head != bitmap) {
+ if (bitmap->previous)
+ bitmap->previous->next = bitmap->next;
+ if (bitmap->next)
+ bitmap->next->previous = bitmap->previous;
+ bitmap->next = bitmap_head;
+ bitmap_head->previous = bitmap;
+ bitmap->previous = NULL;
+ bitmap_head = bitmap;
+ }
+
+ /* image is already decompressed, no change to image states */
+ if (bitmap->sprite_area)
+ return ((char *) (bitmap->sprite_area)) + 16 + 44;
+
+ /* load and/or decompress the image */
+ if (bitmap->filename[0])
+ bitmap_load_file(bitmap);
+ if (bitmap->compressed)
+ bitmap_decompress(bitmap);
+
+ bitmap_maintenance = true;
+ bitmap_maintenance_priority |=
+ (bitmap_direct_used > bitmap_direct_size * 1.1);
+
+ if (bitmap->sprite_area)
+ return ((char *) (bitmap->sprite_area)) + 16 + 44;
+ return NULL;
}
@@ -166,10 +391,7 @@ char *bitmap_get_buffer(struct bitmap *bitmap)
size_t bitmap_get_rowstride(struct bitmap *bitmap)
{
- osspriteop_header *sprite;
- assert(bitmap);
- sprite = (osspriteop_header *) (&(bitmap->sprite_area) + 1);
- return (sprite->width + 1) * 4;
+ return bitmap->width * 4;
}
@@ -181,7 +403,29 @@ size_t bitmap_get_rowstride(struct bitmap *bitmap)
void bitmap_destroy(struct bitmap *bitmap)
{
+ unsigned int area_size;
+
assert(bitmap);
+
+ /* delink from list */
+ bitmap_maintenance = true;
+ if (bitmap_head == bitmap)
+ bitmap_head = bitmap->next;
+ if (bitmap->previous)
+ bitmap->previous->next = bitmap->next;
+ if (bitmap->next)
+ bitmap->next->previous = bitmap->previous;
+
+ /* destroy bitmap */
+ if (bitmap->sprite_area) {
+ area_size = 16 + 44 + bitmap->width * bitmap->height * 4;
+ bitmap_direct_used -= area_size;
+ free(bitmap->sprite_area);
+ }
+ if (bitmap->compressed)
+ free(bitmap->compressed);
+ if (bitmap->filename[0])
+ bitmap_delete_file(bitmap);
free(bitmap);
}
@@ -190,15 +434,19 @@ void bitmap_destroy(struct bitmap *bitmap)
* Save a bitmap in the platform's native format.
*
* \param bitmap a bitmap, as returned by bitmap_create()
- * \param path pathname for file
+ * \param path pathname for file
* \return true on success, false on error and error reported
*/
bool bitmap_save(struct bitmap *bitmap, const char *path)
{
os_error *error;
+ if (!bitmap->sprite_area)
+ bitmap_get_buffer(bitmap);
+ if (!bitmap->sprite_area)
+ return false;
error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
- &(bitmap->sprite_area), path);
+ (bitmap->sprite_area), path);
if (error) {
LOG(("xosspriteop_save_sprite_file: 0x%x: %s",
error->errnum, error->errmess));
@@ -207,3 +455,286 @@ bool bitmap_save(struct bitmap *bitmap, const char *path)
}
return true;
}
+
+
+/**
+ * The bitmap image has changed, so flush any persistant cache.
+ *
+ * \param bitmap a bitmap, as returned by bitmap_create()
+ */
+void bitmap_modified(struct bitmap *bitmap) {
+ bitmap->modified = true;
+}
+
+
+/**
+ * Performs routine maintenance.
+ */
+void bitmap_maintain(void)
+{
+ unsigned int memory;
+ struct bitmap *bitmap = bitmap_head;
+ struct bitmap_compressed_header *header;
+ unsigned int maintain_direct_size;
+
+// LOG(("Performing maintenance."));
+
+ if (!bitmap) {
+ bitmap_maintenance = false;
+ bitmap_maintenance_priority = false;
+ return;
+ }
+ maintain_direct_size = bitmap_direct_size;
+ if (!bitmap_maintenance_priority)
+ maintain_direct_size = maintain_direct_size * 0.7;
+
+ /* we don't change the first bitmap_MEMORY entries as they
+ * will automatically be loaded/decompressed from whatever state
+ * they are in when neeeded. */
+ for (memory = 0; bitmap && (memory < maintain_direct_size);
+ bitmap = bitmap->next)
+ if (bitmap->sprite_area)
+ memory += bitmap->width * bitmap->height * 4;
+ if (!bitmap) {
+ bitmap_maintenance = bitmap_maintenance_priority;
+ bitmap_maintenance_priority = false;
+ return;
+ }
+
+ /* under heavy loads, we ignore compression */
+ if (!bitmap_maintenance_priority) {
+ /* for the next section, up until bitmap_COMPRESSED we
+ * forcibly compress the data if it's currently held directly
+ * in memory */
+ for (memory = 0; bitmap && (memory < bitmap_compressed_size);
+ bitmap = bitmap->next) {
+ if (bitmap->sprite_area) {
+ bitmap_compress(bitmap);
+ return;
+ }
+ if (bitmap->compressed) {
+ header = (struct bitmap_compressed_header *)
+ bitmap->compressed;
+ memory += header->input_size +
+ sizeof(struct bitmap_compressed_header);
+ }
+ }
+ if (!bitmap) {
+ bitmap_maintenance = false;
+ return;
+ }
+ }
+
+ /* for the remaining entries we dump to disk */
+ for (; bitmap; bitmap = bitmap->next) {
+ if ((bitmap->sprite_area) || (bitmap->compressed)) {
+ if (bitmap_maintenance_priority) {
+ if (bitmap->sprite_area)
+ bitmap_save_file(bitmap);
+
+ } else {
+ bitmap_save_file(bitmap);
+ return;
+ }
+ }
+ }
+ bitmap_maintenance = bitmap_maintenance_priority;
+ bitmap_maintenance_priority = false;
+}
+
+
+void bitmap_decompress(struct bitmap *bitmap)
+{
+ unsigned int area_size;
+ _kernel_oserror *error;
+ int output_size;
+ struct bitmap_compressed_header *header;
+
+ assert(bitmap->compressed);
+
+ /* create the image memory/header to decompress to */
+ if (!bitmap_initialise(bitmap, false))
+ return;
+
+ /* decompress the data */
+ output_size = bitmap->width * bitmap->height * 4 +
+ sizeof(struct osspriteop_header);
+ error = _swix(Tinct_Decompress, _IN(0) | _IN(2) | _IN(3) | _IN(7),
+ bitmap->compressed,
+ (char *)(bitmap->sprite_area + 1),
+ output_size,
+ 0);
+ if (error) {
+ LOG(("Decompression error"));
+ free(bitmap->sprite_area);
+ bitmap->sprite_area = NULL;
+ } else {
+// LOG(("Decompressed"));
+ header = (struct bitmap_compressed_header *)bitmap->compressed;
+ area_size = header->input_size +
+ sizeof(struct bitmap_compressed_header);
+ bitmap_compressed_used -= area_size;
+ free(bitmap->compressed);
+ bitmap->compressed = NULL;
+ area_size = 16 + 44 + bitmap->width * bitmap->height * 4;
+ bitmap_direct_used += area_size;
+ }
+}
+
+
+void bitmap_compress(struct bitmap *bitmap)
+{
+ unsigned int area_size;
+ _kernel_oserror *error;
+ char *output;
+ unsigned int output_size, new_size;
+ unsigned int flags = 0;
+ float calc;
+
+ /* get the maximum output size (33/32 * size) */
+ output_size = ((bitmap->width * bitmap->height * 4 * 33) >> 5) +
+ sizeof(struct bitmap_compressed_header);
+ output = malloc(output_size);
+ if (!output)
+ return;
+
+ /* compress the data */
+ if (bitmap->opaque)
+ flags |= tinct_OPAQUE_IMAGE;
+ error = _swix(Tinct_Compress, _IN(0) | _IN(2) | _IN(7) | _OUT(0),
+ (char *)(bitmap->sprite_area + 1),
+ output,
+ flags,
+ &new_size);
+ if (error) {
+ LOG(("Compression error"));
+ free(output);
+ } else {
+ bitmap->compressed = realloc(output, new_size);
+ if (!bitmap->compressed) {
+ free(output);
+ } else {
+ bitmap_compressed_used += new_size;
+ if (bitmap->sprite_area) {
+ area_size = 16 + 44 + bitmap->width *
+ bitmap->height * 4;
+ bitmap_direct_used -= area_size;
+ free(bitmap->sprite_area);
+ }
+ bitmap->sprite_area = NULL;
+ calc = (100 / (float)output_size) * new_size;
+// LOG(("Compression: %i->%i, %.3f%%",
+// output_size, new_size, calc));
+ }
+ }
+}
+
+void bitmap_load_file(struct bitmap *bitmap)
+{
+ unsigned int area_size;
+ int len;
+ fileswitch_object_type obj_type;
+ os_error *error;
+
+ assert(bitmap->filename);
+
+ sprintf(bitmap_filename, "%s.%s", CACHE_FILENAME_PREFIX,
+ bitmap->filename);
+ error = xosfile_read_stamped_no_path(bitmap_filename,
+ &obj_type, 0, 0, &len, 0, 0);
+ if ((error) || (obj_type != fileswitch_IS_FILE))
+ return;
+ bitmap->compressed = malloc(len);
+ if (!bitmap->compressed)
+ return;
+ error = xosfile_load_stamped_no_path(bitmap_filename,
+ bitmap->compressed, 0, 0, 0, 0, 0);
+ if (error) {
+ free(bitmap->compressed);
+ bitmap->compressed = NULL;
+ return;
+ } else {
+// LOG(("Loaded file from disk"));
+ if (strncmp(bitmap->compressed + 8, "bitmap", 6)) {
+ bitmap->sprite_area =
+ (osspriteop_area *)bitmap->compressed;
+ bitmap->compressed = NULL;
+ area_size = 16 + 44 +
+ bitmap->width * bitmap->height * 4;
+ bitmap_direct_used += area_size;
+ } else {
+ bitmap_compressed_used -= len;
+ }
+ if (bitmap->modified)
+ bitmap_delete_file(bitmap);
+ }
+}
+
+
+void bitmap_save_file(struct bitmap *bitmap)
+{
+ unsigned int area_size;
+ char *filename;
+ os_error *error;
+ struct bitmap_compressed_header *header;
+
+ assert(bitmap->compressed || bitmap->sprite_area);
+
+ /* unmodified bitmaps will still have their file available */
+ if (!bitmap->modified && bitmap->filename[0]) {
+ if (bitmap->sprite_area)
+ free(bitmap->sprite_area);
+ bitmap->sprite_area = NULL;
+ if (bitmap->compressed)
+ free(bitmap->compressed);
+ bitmap->compressed = NULL;
+ return;
+ }
+
+ /* dump the data (compressed or otherwise) to disk */
+ filename = ro_filename_request();
+ strcpy(bitmap->filename, filename);
+ sprintf(bitmap_filename, "%s.%s", CACHE_FILENAME_PREFIX,
+ bitmap->filename);
+ if (bitmap->compressed) {
+ header = (struct bitmap_compressed_header *)bitmap->compressed;
+ area_size = header->input_size +
+ sizeof(struct bitmap_compressed_header);
+ error = xosfile_save_stamped(bitmap_filename, 0xffd,
+ bitmap->compressed,
+ bitmap->compressed + area_size);
+ } else {
+ area_size = bitmap->width * bitmap->height * 4 +
+ sizeof(osspriteop_header) +
+ sizeof(osspriteop_area);
+ error = xosfile_save_stamped(bitmap_filename, 0xffd,
+ (char *)bitmap->sprite_area,
+ ((char *)bitmap->sprite_area) + area_size);
+ }
+
+ if (error) {
+ LOG(("File save error"));
+ bitmap->filename[0] = 0;
+ } else {
+ if (bitmap->sprite_area) {
+ bitmap_direct_used -= area_size;
+ free(bitmap->sprite_area);
+ }
+ bitmap->sprite_area = NULL;
+ if (bitmap->compressed) {
+ bitmap_compressed_used -= area_size;
+ free(bitmap->compressed);
+ }
+ bitmap->compressed = NULL;
+ bitmap->modified = false;
+// LOG(("Saved file to disk"));
+ }
+}
+
+
+void bitmap_delete_file(struct bitmap *bitmap)
+{
+ assert(bitmap->filename[0]);
+ ro_filename_release(bitmap->filename);
+ bitmap->filename[0] = 0;
+}
diff --git a/riscos/bitmap.h b/riscos/bitmap.h
index 7a5fbf5c7..2ce8f04a9 100644
--- a/riscos/bitmap.h
+++ b/riscos/bitmap.h
@@ -1,20 +1,45 @@
/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
- * http://www.opensource.org/licenses/gpl-license
+ * http://www.opensource.org/licenses/gpl-license
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*/
#ifndef _NETSURF_RISCOS_BITMAP_H_
#define _NETSURF_RISCOS_BITMAP_H_
+#include "oslib/osspriteop.h"
+
struct osspriteop_area;
struct bitmap {
int width;
int height;
- bool opaque;
- osspriteop_area sprite_area;
+ bool opaque;
+ bool modified;
+ bool persistent;
+
+ osspriteop_area *sprite_area; /** Uncompressed data, or NULL */
+ char *compressed; /** Compressed data, or NULL */
+ char filename[12]; /** Data filename, or '/0' */
+
+ struct bitmap *previous; /** Previous bitmap */
+ struct bitmap *next; /** Next bitmap */
+
};
+struct bitmap *bitmap_create_file(int width, int height, char *file);
+void bitmap_initialise_memory(void);
+void bitmap_quit(void);
+void bitmap_maintain(void);
+
+/** Whether maintenance of the pool states is needed
+*/
+extern bool bitmap_maintenance;
+
+/** Whether maintenance of the pool is high priority
+*/
+extern bool bitmap_maintenance_priority;
+
+
#endif
diff --git a/riscos/global_history.c b/riscos/global_history.c
index ac04a8141..307d021bd 100644
--- a/riscos/global_history.c
+++ b/riscos/global_history.c
@@ -45,6 +45,9 @@ static int global_history_base_node_count = 0;
static char *global_history_recent_url[GLOBAL_HISTORY_RECENT_URLS];
static int global_history_recent_count = 0;
+static bool global_history_init;
+
+
static void ro_gui_global_history_initialise_nodes(void);
static void ro_gui_global_history_initialise_node(const char *title,
time_t base, int days_back);
@@ -164,6 +167,7 @@ void ro_gui_global_history_initialise(void) {
LOG(("Failed to open file '%s' for reading",
GLOBAL_HISTORY_READ));
else {
+ global_history_init = true;
while (fgets(s, MAXIMUM_URL_LENGTH, fp)) {
if (s[strlen(s) - 1] == '\n')
s[strlen(s) - 1] = '\0';
@@ -172,6 +176,7 @@ void ro_gui_global_history_initialise(void) {
LOG(("Error reading global history"));
warn_user("HistoryCorrupt", 0);
fclose(fp);
+ global_history_init = false;
return;
}
if (s[strlen(s) - 1] == '\n')
@@ -181,12 +186,14 @@ void ro_gui_global_history_initialise(void) {
LOG(("No memory to read global history node"));
warn_user("NoMemory", 0);
fclose(fp);
+ global_history_init = false;
return;
}
if (!fgets(s, MAXIMUM_URL_LENGTH, fp)) {
LOG(("Error reading global history"));
warn_user("HistoryCorrupt", 0);
fclose(fp);
+ global_history_init = false;
return;
}
node_filetype = atoi(s);
@@ -194,6 +201,7 @@ void ro_gui_global_history_initialise(void) {
LOG(("Error reading global history"));
warn_user("HistoryCorrupt", 0);
fclose(fp);
+ global_history_init = false;
return;
}
node_visited = atoi(s);
@@ -204,6 +212,7 @@ void ro_gui_global_history_initialise(void) {
free(node_url);
node_url = NULL;
}
+ global_history_init = false;
fclose(fp);
}
}
@@ -367,14 +376,24 @@ int ro_gui_global_history_help(int x, int y) {
* \param g the gui_window to add to the global history
*/
void global_history_add(struct gui_window *g) {
+ url_func_result res;
+ char *norm_url = NULL;
+
assert(g);
if ((!g->bw->current_content) || (!global_history_tree))
return;
+ res = url_normalize(g->bw->current_content->url, &norm_url);
+ if (res != URL_FUNC_OK) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+
ro_gui_global_history_add(g->bw->current_content->title,
- g->bw->current_content->url, time(NULL),
+ norm_url, time(NULL),
ro_content_filetype(g->bw->current_content));
+ free(norm_url);
}
@@ -412,8 +431,9 @@ void ro_gui_global_history_add(char *title, char *url, int visit_date,
tree_link_node(link, parent, before);
tree_recalculate_node_positions(
global_history_tree->root);
- tree_redraw_area(global_history_tree,
- 0, 0, 16384, 16384);
+ if (!global_history_init)
+ tree_redraw_area(global_history_tree,
+ 0, 0, 16384, 16384);
break;
}
}
@@ -423,13 +443,13 @@ void ro_gui_global_history_add(char *title, char *url, int visit_date,
*/
node = tree_create_URL_node_brief(parent, title, url, filetype,
visit_date);
- if (node) {
+ if (node && !global_history_init)
tree_redraw_area(global_history_tree,
node->box.x - NODE_INSTEP,
0, NODE_INSTEP, 16384);
+ if (!global_history_init)
tree_handle_node_changed(global_history_tree, node,
- false, true);
- }
+ true, false);
/* Remove any duplicate URL from within the parent node.
* This must be done after the duplicate has been created as