summaryrefslogtreecommitdiff
path: root/image/image_cache.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-05-23 23:32:16 +0100
committerVincent Sanders <vince@kyllikki.org>2016-05-23 23:32:16 +0100
commit3224d7121aff91ab8d888831dc493ef621e3dd39 (patch)
tree5e4585fd78b6b247a5e602ea1a1d55e0dfe206fb /image/image_cache.c
parent93be8d805e7e1f32638015770446476fef22ceac (diff)
downloadnetsurf-3224d7121aff91ab8d888831dc493ef621e3dd39.tar.gz
netsurf-3224d7121aff91ab8d888831dc493ef621e3dd39.tar.bz2
move image content handlers to accomodate core build changes
Diffstat (limited to 'image/image_cache.c')
-rw-r--r--image/image_cache.c797
1 files changed, 0 insertions, 797 deletions
diff --git a/image/image_cache.c b/image/image_cache.c
deleted file mode 100644
index 9f217f860..000000000
--- a/image/image_cache.c
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "content/content_protected.h"
-#include "desktop/gui_misc.h"
-#include "desktop/gui_internal.h"
-
-#include "image/bitmap.h"
-#include "image/image_cache.h"
-#include "image/image.h"
-
-/** Age of an entry within the cache
- *
- * type deffed away so it can be readily changed later perhaps to a
- * wallclock time structure.
- */
-typedef unsigned int cache_age;
-
-/** Image cache entry
- */
-struct image_cache_entry_s {
- struct image_cache_entry_s *next; /* next cache entry in list */
- struct image_cache_entry_s *prev; /* previous cache entry in list */
-
- struct content *content; /** content is used as a key */
- struct bitmap *bitmap; /** associated bitmap entry */
- /** Conversion routine */
- image_cache_convert_fn *convert;
-
- /* Statistics for replacement algorithm */
-
- unsigned int redraw_count; /**< number of times object has been drawn */
- cache_age redraw_age; /**< Age of last redraw */
- size_t bitmap_size; /**< size if storage occupied by bitmap */
- cache_age bitmap_age; /**< Age of last conversion to a bitmap by cache*/
-
- int conversion_count; /**< Number of times image has been converted */
-};
-
-/** Current state of the cache.
- *
- * Global state of the cache. entries "age" is determined based on a
- * monotonically incrementing operation count. This avoids issues with
- * using wall clock time while allowing the LRU algorithm to work
- * sensibly.
- */
-struct image_cache_s {
- /** Cache parameters */
- struct image_cache_parameters params;
-
- /** The "age" of the current operation */
- cache_age current_age;
-
- /* The objects the cache holds */
- struct image_cache_entry_s *entries;
-
-
- /* Statistics for management algorithm */
-
- /** total size of bitmaps currently allocated */
- size_t total_bitmap_size;
-
- /** Total count of bitmaps currently allocated */
- int bitmap_count;
-
- /** Maximum size of bitmaps allocated at any one time */
- size_t max_bitmap_size;
- /** The number of objects when maximum bitmap usage occoured */
- int max_bitmap_size_count;
-
- /** Maximum count of bitmaps allocated at any one time */
- int max_bitmap_count;
- /** The size of the bitmaps when the max count occoured */
- size_t max_bitmap_count_size;
-
- /** Bitmap was not available at plot time required conversion */
- int miss_count;
- uint64_t miss_size;
- /** Bitmap was available at plot time required no conversion */
- int hit_count;
- uint64_t hit_size;
- /** Bitmap was not available at plot time and required
- * conversion which failed.
- */
- int fail_count;
- uint64_t fail_size;
-
- /* Cache entry freed without ever being redrawn */
- int total_unrendered;
- /** Bitmap was available but never required - wasted conversions */
- int specultive_miss_count;
-
- /** Total number of additional (after the first) conversions */
- int total_extra_conversions;
- /** counts total number of images with more than one conversion */
- int total_extra_conversions_count;
-
- /** Bitmap with most conversions was converted this many times */
- int peak_conversions;
- /** Size of bitmap with most conversions */
- unsigned int peak_conversions_size;
-};
-
-/** image cache state */
-static struct image_cache_s *image_cache = NULL;
-
-
-/** Find the nth cache entry
- */
-static struct image_cache_entry_s *image_cache__findn(int entryn)
-{
- struct image_cache_entry_s *found;
-
- found = image_cache->entries;
- while ((found != NULL) && (entryn > 0)) {
- entryn--;
- found = found->next;
- }
- return found;
-}
-
-/** Find the cache entry for a content
- */
-static struct image_cache_entry_s *image_cache__find(const struct content *c)
-{
- struct image_cache_entry_s *found;
-
- found = image_cache->entries;
- while ((found != NULL) && (found->content != c)) {
- found = found->next;
- }
- return found;
-}
-
-static void image_cache_stats_bitmap_add(struct image_cache_entry_s *centry)
-{
- centry->bitmap_age = image_cache->current_age;
- centry->conversion_count++;
-
- image_cache->total_bitmap_size += centry->bitmap_size;
- image_cache->bitmap_count++;
-
- if (image_cache->total_bitmap_size > image_cache->max_bitmap_size) {
- image_cache->max_bitmap_size = image_cache->total_bitmap_size;
- image_cache->max_bitmap_size_count = image_cache->bitmap_count;
-
- }
-
- if (image_cache->bitmap_count > image_cache->max_bitmap_count) {
- image_cache->max_bitmap_count = image_cache->bitmap_count;
- image_cache->max_bitmap_count_size = image_cache->total_bitmap_size;
- }
-
- if (centry->conversion_count == 2) {
- image_cache->total_extra_conversions_count++;
- }
-
- if (centry->conversion_count > 1) {
- image_cache->total_extra_conversions++;
- }
-
- if ((centry->conversion_count > image_cache->peak_conversions) ||
- (centry->conversion_count == image_cache->peak_conversions &&
- centry->bitmap_size > image_cache->peak_conversions_size)) {
- image_cache->peak_conversions = centry->conversion_count;
- image_cache->peak_conversions_size = centry->bitmap_size;
- }
-}
-
-static void image_cache__link(struct image_cache_entry_s *centry)
-{
- centry->next = image_cache->entries;
- centry->prev = NULL;
- if (centry->next != NULL) {
- centry->next->prev = centry;
- }
- image_cache->entries = centry;
-}
-
-static void image_cache__unlink(struct image_cache_entry_s *centry)
-{
- /* unlink entry */
- if (centry->prev == NULL) {
- /* first in list */
- if (centry->next != NULL) {
- centry->next->prev = centry->prev;
- image_cache->entries = centry->next;
- } else {
- /* empty list */
- image_cache->entries = NULL;
- }
- } else {
- centry->prev->next = centry->next;
-
- if (centry->next != NULL) {
- centry->next->prev = centry->prev;
- }
- }
-}
-
-static void image_cache__free_bitmap(struct image_cache_entry_s *centry)
-{
- if (centry->bitmap != NULL) {
-#ifdef IMAGE_CACHE_VERBOSE
- LOG("Freeing bitmap %p size %d age %d redraw count %d", centry->bitmap, centry->bitmap_size, image_cache->current_age - centry->bitmap_age, centry->redraw_count);
-#endif
- guit->bitmap->destroy(centry->bitmap);
- centry->bitmap = NULL;
- image_cache->total_bitmap_size -= centry->bitmap_size;
- image_cache->bitmap_count--;
- if (centry->redraw_count == 0) {
- image_cache->specultive_miss_count++;
- }
- }
-
-}
-
-/* free cache entry */
-static void image_cache__free_entry(struct image_cache_entry_s *centry)
-{
-#ifdef IMAGE_CACHE_VERBOSE
- LOG("freeing %p ", centry);
-#endif
-
- if (centry->redraw_count == 0) {
- image_cache->total_unrendered++;
- }
-
- image_cache__free_bitmap(centry);
-
- image_cache__unlink(centry);
-
- free(centry);
-}
-
-/** Cache cleaner */
-static void image_cache__clean(struct image_cache_s *icache)
-{
- struct image_cache_entry_s *centry = icache->entries;
-
- while (centry != NULL) {
- if ((icache->current_age - centry->redraw_age) >
- icache->params.bg_clean_time) {
- /* only consider older entries, avoids active entries */
- if ((icache->total_bitmap_size >
- (icache->params.limit - icache->params.hysteresis)) &&
- (rand() > (RAND_MAX / 2))) {
- image_cache__free_bitmap(centry);
- }
- }
- centry=centry->next;
- }
-}
-
-/** Cache background scheduled callback. */
-static void image_cache__background_update(void *p)
-{
- struct image_cache_s *icache = p;
-
- /* increment current cache age */
- icache->current_age += icache->params.bg_clean_time;
-
-#ifdef IMAGE_CACHE_VERBOSE
- LOG("Cache age %ds", icache->current_age / 1000);
-#endif
-
- image_cache__clean(icache);
-
- guit->misc->schedule(icache->params.bg_clean_time,
- image_cache__background_update,
- icache);
-}
-
-/* exported interface documented in image_cache.h */
-struct bitmap *image_cache_get_bitmap(const struct content *c)
-{
- struct image_cache_entry_s *centry;
-
- centry = image_cache__find(c);
- if (centry == NULL) {
- return NULL;
- }
-
- if (centry->bitmap == NULL) {
- if (centry->convert != NULL) {
- centry->bitmap = centry->convert(centry->content);
- }
-
- if (centry->bitmap != NULL) {
- image_cache_stats_bitmap_add(centry);
- image_cache->miss_count++;
- image_cache->miss_size += centry->bitmap_size;
- } else {
- image_cache->fail_count++;
- image_cache->fail_size += centry->bitmap_size;
- }
- } else {
- image_cache->hit_count++;
- image_cache->hit_size += centry->bitmap_size;
- }
-
- return centry->bitmap;
-}
-
-/* exported interface documented in image_cache.h */
-bool image_cache_speculate(struct content *c)
-{
- bool decision = false;
-
- /* If the cache is below its target usage and the bitmap is
- * small enough speculate.
- */
- if ((image_cache->total_bitmap_size < image_cache->params.limit) &&
- (c->size <= image_cache->params.speculative_small)) {
-#ifdef IMAGE_CACHE_VERBOSE
- LOG("content size (%d) is smaller than minimum (%d)", c->size, SPECULATE_SMALL);
-#endif
- decision = true;
- }
-
-#ifdef IMAGE_CACHE_VERBOSE
- LOG("returning %d", decision);
-#endif
- return decision;
-}
-
-/* exported interface documented in image_cache.h */
-struct bitmap *image_cache_find_bitmap(struct content *c)
-{
- struct image_cache_entry_s *centry;
-
- centry = image_cache__find(c);
- if (centry == NULL) {
- return NULL;
- }
-
- return centry->bitmap;
-}
-
-/* exported interface documented in image_cache.h */
-nserror
-image_cache_init(const struct image_cache_parameters *image_cache_parameters)
-{
- image_cache = calloc(1, sizeof(struct image_cache_s));
- if (image_cache == NULL) {
- return NSERROR_NOMEM;
- }
-
- image_cache->params = *image_cache_parameters;
-
- guit->misc->schedule(image_cache->params.bg_clean_time,
- image_cache__background_update,
- image_cache);
-
- LOG("Image cache initilised with a limit of %" PRIsizet " hysteresis of %"PRIsizet,
- image_cache->params.limit, image_cache->params.hysteresis);
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in image_cache.h */
-nserror image_cache_fini(void)
-{
- unsigned int op_count;
-
- guit->misc->schedule(-1, image_cache__background_update, image_cache);
-
- LOG("Size at finish %" PRIsizet " (in %d)",
- image_cache->total_bitmap_size, image_cache->bitmap_count);
-
- while (image_cache->entries != NULL) {
- image_cache__free_entry(image_cache->entries);
- }
-
- op_count = image_cache->hit_count +
- image_cache->miss_count +
- image_cache->fail_count;
-
- LOG("Age %ds", image_cache->current_age / 1000);
- LOG("Peak size %" PRIsizet " (in %d)",
- image_cache->max_bitmap_size, image_cache->max_bitmap_size_count);
- LOG("Peak image count %d (size %" PRIsizet ")",
- image_cache->max_bitmap_count, image_cache->max_bitmap_count_size);
-
- if (op_count > 0) {
- uint64_t op_size;
-
- op_size = image_cache->hit_size +
- image_cache->miss_size +
- image_cache->fail_size;
-
- LOG("Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
- op_count,
- image_cache->hit_count,
- image_cache->miss_count,
- image_cache->fail_count,
- (image_cache->hit_count * 100) / op_count,
- (image_cache->miss_count * 100) / op_count,
- (image_cache->fail_count * 100) / op_count);
- LOG("Cache total/hit/miss/fail (size) %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64" (100%%/%"PRId64"%%/%"PRId64"%%/%"PRId64"%%)",
- op_size,
- image_cache->hit_size,
- image_cache->miss_size,
- image_cache->fail_size,
- (image_cache->hit_size * 100) / op_size,
- (image_cache->miss_size * 100) / op_size,
- (image_cache->fail_size * 100) / op_size);
- }
-
- LOG("Total images never rendered: %d (includes %d that were converted)",
- image_cache->total_unrendered,
- image_cache->specultive_miss_count);
-
- LOG("Total number of excessive conversions: %d (from %d images converted more than once)",
- image_cache->total_extra_conversions,
- image_cache->total_extra_conversions_count);
-
- LOG("Bitmap of size %d had most (%d) conversions",
- image_cache->peak_conversions_size,
- image_cache->peak_conversions);
-
- free(image_cache);
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in image_cache.h */
-nserror image_cache_add(struct content *content,
- struct bitmap *bitmap,
- image_cache_convert_fn *convert)
-{
- struct image_cache_entry_s *centry;
-
- /* bump the cache age by a ms to ensure multiple items are not
- * added at exactly the same time
- */
- image_cache->current_age++;
-
- centry = image_cache__find(content);
- if (centry == NULL) {
- /* new cache entry, content not previously added */
- centry = calloc(1, sizeof(struct image_cache_entry_s));
- if (centry == NULL) {
- return NSERROR_NOMEM;
- }
- image_cache__link(centry);
- centry->content = content;
-
- centry->bitmap_size = content->width * content->height * 4;
- }
-
- LOG("centry %p, content %p, bitmap %p", centry, content, bitmap);
-
- centry->convert = convert;
-
- /* set bitmap entry if one is passed, free extant one if present */
- if (bitmap != NULL) {
- if (centry->bitmap != NULL) {
- guit->bitmap->destroy(centry->bitmap);
- } else {
- image_cache_stats_bitmap_add(centry);
- }
- centry->bitmap = bitmap;
- } else {
- /* no bitmap, check to see if we should speculatively convert */
- if ((centry->convert != NULL) &&
- (image_cache_speculate(content) == true)) {
- centry->bitmap = centry->convert(centry->content);
-
- if (centry->bitmap != NULL) {
- image_cache_stats_bitmap_add(centry);
- } else {
- image_cache->fail_count++;
- }
- }
- }
-
-
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in image_cache.h */
-nserror image_cache_remove(struct content *content)
-{
- struct image_cache_entry_s *centry;
-
- /* get the cache entry */
- centry = image_cache__find(content);
- if (centry == NULL) {
- LOG("Could not find cache entry for content (%p)", content);
- return NSERROR_NOT_FOUND;
- }
-
- image_cache__free_entry(centry);
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in image_cache.h */
-int image_cache_snsummaryf(char *string, size_t size, const char *fmt)
-{
- size_t slen = 0; /* current output string length */
- int fmtc = 0; /* current index into format string */
- bool pct;
- unsigned int op_count;
- uint64_t op_size;
-
- op_count = image_cache->hit_count +
- image_cache->miss_count +
- image_cache->fail_count;
-
- op_size = image_cache->hit_size +
- image_cache->miss_size +
- image_cache->fail_size;
-
- while((slen < size) && (fmt[fmtc] != 0)) {
- if (fmt[fmtc] == '%') {
- fmtc++;
-
- /* check for percentage modifier */
- if (fmt[fmtc] == 'p') {
- fmtc++;
- pct = true;
- } else {
- pct = false;
- }
-
-#define FMTCHR(chr,fmt,var) case chr : \
-slen += snprintf(string + slen, size - slen, "%"fmt, image_cache->var); break
-
-#define FMTPCHR(chr,fmt,var,div) \
-case chr : \
- if (pct) { \
- if (div > 0) { \
- slen += snprintf(string + slen, size - slen, "%"PRId64, (uint64_t)((image_cache->var * 100) / div)); \
- } else { \
- slen += snprintf(string + slen, size - slen, "100"); \
- } \
- } else { \
- slen += snprintf(string + slen, size - slen, "%"fmt, image_cache->var); \
- } break
-
-
- switch (fmt[fmtc]) {
- case '%':
- string[slen] = '%';
- slen++;
- break;
-
- FMTCHR('a', PRIssizet, params.limit);
- FMTCHR('b', PRIssizet, params.hysteresis);
- FMTCHR('c', PRIssizet, total_bitmap_size);
- FMTCHR('d', "d", bitmap_count);
- FMTCHR('e', "d", current_age / 1000);
- FMTCHR('f', PRIssizet, max_bitmap_size);
- FMTCHR('g', "d", max_bitmap_size_count);
- FMTCHR('h', "d", max_bitmap_count);
- FMTCHR('i', PRIssizet, max_bitmap_count_size);
-
-
- case 'j':
- slen += snprintf(string + slen, size - slen,
- "%d", pct?100:op_count);
- break;
-
- FMTPCHR('k', "d", hit_count, op_count);
- FMTPCHR('l', "d", miss_count, op_count);
- FMTPCHR('m', "d", fail_count, op_count);
-
- case 'n':
- slen += snprintf(string + slen, size - slen,
- "%"PRId64, pct?100:op_size);
- break;
-
- FMTPCHR('o', PRId64, hit_size, op_size);
- FMTPCHR('q', PRId64, miss_size, op_size);
- FMTPCHR('r', PRId64, fail_size, op_size);
-
- FMTCHR('s', "d", total_unrendered);
- FMTCHR('t', "d", specultive_miss_count);
- FMTCHR('u', "d", total_extra_conversions);
- FMTCHR('v', "d", total_extra_conversions_count);
- FMTCHR('w', "d", peak_conversions_size);
- FMTCHR('x', "d", peak_conversions);
-
-
- }
-#undef FMTCHR
-#undef FMTPCHR
-
- fmtc++;
- } else {
- string[slen] = fmt[fmtc];
- slen++;
- fmtc++;
- }
- }
-
- /* Ensure that we NUL-terminate the output */
- string[min(slen, size - 1)] = '\0';
-
- return slen;
-}
-
-/* exported interface documented in image_cache.h */
-int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
- const char *fmt)
-{
- struct image_cache_entry_s *centry;
- size_t slen = 0; /* current output string length */
- int fmtc = 0; /* current index into format string */
- lwc_string *origin; /* current entry's origin */
-
- centry = image_cache__findn(entryn);
- if (centry == NULL)
- return -1;
-
- while((slen < size) && (fmt[fmtc] != 0)) {
- if (fmt[fmtc] == '%') {
- fmtc++;
- switch (fmt[fmtc]) {
- case 'e':
- slen += snprintf(string + slen, size - slen,
- "%d", entryn);
- break;
-
- case 'r':
- slen += snprintf(string + slen, size - slen,
- "%u", centry->redraw_count);
- break;
-
- case 'a':
- slen += snprintf(string + slen, size - slen,
- "%.2f", (float)((image_cache->current_age - centry->redraw_age)) / 1000);
- break;
-
-
- case 'c':
- slen += snprintf(string + slen, size - slen,
- "%d", centry->conversion_count);
- break;
-
- case 'g':
- slen += snprintf(string + slen, size - slen,
- "%.2f", (float)((image_cache->current_age - centry->bitmap_age)) / 1000);
- break;
-
- case 'k':
- slen += snprintf(string + slen, size - slen,
- "%p", centry->content);
- break;
-
- case 'U':
- slen += snprintf(string + slen, size - slen,
- "%s", nsurl_access(llcache_handle_get_url(centry->content->llcache)));
- break;
-
- case 'o':
- if (nsurl_has_component(llcache_handle_get_url(
- centry->content->llcache),
- NSURL_HOST)) {
- origin = nsurl_get_component(
- llcache_handle_get_url(
- centry->content->
- llcache),
- NSURL_HOST);
-
- slen += snprintf(string + slen,
- size - slen, "%s",
- lwc_string_data(
- origin));
-
- lwc_string_unref(origin);
- } else {
- slen += snprintf(string + slen,
- size - slen, "%s",
- "localhost");
- }
- break;
-
- case 's':
- if (centry->bitmap != NULL) {
- slen += snprintf(string + slen,
- size - slen,
- "%" PRIssizet,
- centry->bitmap_size);
- } else {
- slen += snprintf(string + slen,
- size - slen,
- "0");
- }
- break;
- }
- fmtc++;
- } else {
- string[slen] = fmt[fmtc];
- slen++;
- fmtc++;
- }
- }
-
- /* Ensure that we NUL-terminate the output */
- string[min(slen, size - 1)] = '\0';
-
- return slen;
-}
-
-
-/* exported interface documented in image_cache.h */
-bool image_cache_redraw(struct content *c,
- struct content_redraw_data *data,
- const struct rect *clip,
- const struct redraw_context *ctx)
-{
- struct image_cache_entry_s *centry;
-
- /* get the cache entry */
- centry = image_cache__find(c);
- if (centry == NULL) {
- LOG("Could not find cache entry for content (%p)", c);
- return false;
- }
-
- if (centry->bitmap == NULL) {
- if (centry->convert != NULL) {
- centry->bitmap = centry->convert(centry->content);
- }
-
- if (centry->bitmap != NULL) {
- image_cache_stats_bitmap_add(centry);
- image_cache->miss_count++;
- image_cache->miss_size += centry->bitmap_size;
- } else {
- image_cache->fail_count++;
- image_cache->fail_size += centry->bitmap_size;
- return false;
- }
- } else {
- image_cache->hit_count++;
- image_cache->hit_size += centry->bitmap_size;
- }
-
-
- /* update statistics */
- centry->redraw_count++;
- centry->redraw_age = image_cache->current_age;
-
- return image_bitmap_plot(centry->bitmap, data, clip, ctx);
-}
-
-void image_cache_destroy(struct content *content)
-{
- struct image_cache_entry_s *centry;
-
- /* get the cache entry */
- centry = image_cache__find(content);
- if (centry == NULL) {
- LOG("Could not find cache entry for content (%p)", content);
- } else {
- image_cache__free_entry(centry);
- }
-}
-
-void *image_cache_get_internal(const struct content *c, void *context)
-{
- return image_cache_get_bitmap(c);
-}
-
-content_type image_cache_content_type(void)
-{
- return CONTENT_IMAGE;
-}