From b88a81b9d9570c3219dc924c3dd2b424d99ee4c3 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Thu, 23 Jun 2005 17:22:28 +0000 Subject: [project @ 2005-06-23 17:22:28 by rjw] Allow images to be unloaded to disk or compressed in memory. Provide thumbnails in all tree windows (hotlist, history). Optimise the application initialisation times. Part 1 of 2. svn path=/import/netsurf/; revision=1761 --- content/url_store.c | 89 +++++++- content/url_store.h | 7 + debug/debug_bitmap.c | 9 + desktop/tree.c | 31 +-- desktop/tree.h | 2 + gtk/gtk_bitmap.c | 9 + image/bitmap.h | 1 + image/gif.c | 4 +- image/gifread.c | 4 +- image/jpeg.c | 1 + image/mng.c | 4 +- render/html.c | 5 + riscos/bitmap.c | 579 ++++++++++++++++++++++++++++++++++++++++++++++-- riscos/bitmap.h | 31 ++- riscos/global_history.c | 32 ++- 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 #include #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 + * Copyright 2005 Richard Wilson */ /** \file @@ -15,14 +16,136 @@ #include #include #include +#include +#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 */ #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 -- cgit v1.2.3