aboutsummaryrefslogtreecommitdiff
path: root/src/dicache.c
diff options
context:
space:
mode:
authorJohannes Hofmann <Johannes.Hofmann@gmx.de>2010-08-20 23:24:19 +0200
committerJohannes Hofmann <Johannes.Hofmann@gmx.de>2010-08-20 23:24:19 +0200
commitf5c598b518d1f906148534d015f50075d3e8242d (patch)
tree21dd70add5b366c3dd80641b77f6b18e0baa009e /src/dicache.c
parente98d02a01ffeb18ede86af025e51ae1ec011c75a (diff)
parent5f0fc0e48b8cbee7e1795935da0abff6627fd498 (diff)
merge
Diffstat (limited to 'src/dicache.c')
-rw-r--r--src/dicache.c375
1 files changed, 238 insertions, 137 deletions
diff --git a/src/dicache.c b/src/dicache.c
index 97ed1915..e700f000 100644
--- a/src/dicache.c
+++ b/src/dicache.c
@@ -9,18 +9,26 @@
* (at your option) any later version.
*/
-#include <sys/time.h> /* for libc5 compatibility */
#include <string.h> /* for memset */
-#include <stdio.h>
#include <stdlib.h>
+#include "msg.h"
#include "image.hh"
+#include "imgbuf.hh"
#include "web.hh"
#include "dicache.h"
-#include "cache.h"
+#include "dpng.h"
+#include "dgif.h"
+#include "djpeg.h"
typedef struct _DICacheNode DICacheNode;
+enum {
+ DIC_Gif,
+ DIC_Png,
+ DIC_Jpeg
+};
+
struct _DICacheNode {
int valid; /* flag */
DilloUrl *url; /* primary "Key" for this dicache entry */
@@ -33,9 +41,9 @@ struct _DICacheNode {
*/
static Dlist *CachedIMGs = NULL;
-static int dicache_size_total; /* invariant: dicache_size_total is
- * the sum of the image sizes (3*w*h)
- * of all the images in the dicache. */
+static uint_t dicache_size_total; /* invariant: dicache_size_total is
+ * the sum of the image sizes (3*w*h)
+ * of all the images in the dicache. */
/*
* Compare two dicache nodes
@@ -78,15 +86,18 @@ static DICacheEntry *Dicache_entry_new(void)
entry->height = 0;
entry->type = DILLO_IMG_TYPE_NOTSET;
entry->cmap = NULL;
- entry->linebuf = NULL;
entry->v_imgbuf = NULL;
entry->RefCount = 1;
entry->TotalSize = 0;
- entry->Y = 0;
entry->ScanNumber = 0;
entry->BitVec = NULL;
entry->State = DIC_Empty;
- entry->version = 0;
+ entry->version = 1;
+
+ entry->Decoder = NULL;
+ entry->DecoderData = NULL;
+ entry->DecodedSize = 0;
+
entry->next = NULL;
return entry;
@@ -96,7 +107,7 @@ static DICacheEntry *Dicache_entry_new(void)
* Add a new entry in the dicache
* (a single node (URL) may have several entries)
*/
-DICacheEntry *a_Dicache_add_entry(const DilloUrl *Url)
+static DICacheEntry *Dicache_add_entry(const DilloUrl *Url)
{
DICacheEntry *entry;
DICacheNode *node;
@@ -127,41 +138,31 @@ DICacheEntry *a_Dicache_add_entry(const DilloUrl *Url)
}
/*
- * Search an entry in the dicache (given the Url).
- * Return value: a pointer to the entry of the _newest_ (i.e. highest)
- * version if found; NULL otherwise.
- */
-DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url)
-{
- DICacheNode *node;
- DICacheEntry *entry;
-
- node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
-
- if (!node || !node->valid)
- return NULL;
-
- for (entry = node->first; (entry && entry->next); entry = entry->next);
-
- return entry;
-}
-
-/*
* Search a particular version of a URL in the Dicache.
* Return value: a pointer to the entry if found; NULL otherwise.
+ *
+ * Notes: DIC_Last means last version of the image.
+ * version zero is not allowed.
*/
-static DICacheEntry *Dicache_get_entry_version(const DilloUrl *Url,
- int version)
+DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version)
{
DICacheNode *node;
- DICacheEntry *entry;
+ DICacheEntry *entry = NULL;
- node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
- entry = (node) ? node->first : NULL;
-
- while (entry && entry->version != version)
- entry = entry->next;
+ dReturn_val_if_fail(version != 0, NULL);
+ node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
+ if (node) {
+ if (version == DIC_Last) {
+ if (node->valid) {
+ entry = node->first;
+ for ( ; (entry && entry->next); entry = entry->next);
+ }
+ } else {
+ entry = node->first;
+ for ( ; entry && entry->version != version; entry = entry->next) ;
+ }
+ }
return entry;
}
@@ -172,7 +173,7 @@ static void Dicache_remove(const DilloUrl *Url, int version)
{
DICacheNode *node;
DICacheEntry *entry, *prev;
-
+ _MSG("Dicache_remove url=%s\n", URL_STR(Url));
node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
prev = entry = (node) ? node->first : NULL;
@@ -182,11 +183,15 @@ static void Dicache_remove(const DilloUrl *Url, int version)
}
if (entry) {
+ _MSG("Dicache_remove Decoder=%p DecoderData=%p\n",
+ entry->Decoder, entry->DecoderData);
/* Eliminate this dicache entry */
dFree(entry->cmap);
- dFree(entry->linebuf);
a_Bitvec_free(entry->BitVec);
- a_Image_imgbuf_unref(entry->v_imgbuf);
+ a_Imgbuf_unref(entry->v_imgbuf);
+ if (entry->Decoder) {
+ entry->Decoder(CA_Abort, entry->DecoderData);
+ }
dicache_size_total -= entry->TotalSize;
if (node->first == entry) {
@@ -206,14 +211,14 @@ static void Dicache_remove(const DilloUrl *Url, int version)
/*
* Unrefs the counter of a dicache entry, and _if_ no DwImage is acessing
- * this buffer, then we call Dicache_free to do the dirty job.
+ * this buffer, then we call Dicache_remove() to do the job.
*/
void a_Dicache_unref(const DilloUrl *Url, int version)
{
DICacheEntry *entry;
- if ((entry = Dicache_get_entry_version(Url, version))) {
- /*if (--entry->RefCount == 0 && (entry->next || !prefs.use_dicache)) {*/
+ _MSG("a_Dicache_unref\n");
+ if ((entry = a_Dicache_get_entry(Url, version))) {
if (--entry->RefCount == 0) {
Dicache_remove(Url, version);
}
@@ -223,12 +228,11 @@ void a_Dicache_unref(const DilloUrl *Url, int version)
/*
* Refs the counter of a dicache entry.
*/
-
DICacheEntry* a_Dicache_ref(const DilloUrl *Url, int version)
{
DICacheEntry *entry;
- if ((entry = Dicache_get_entry_version(Url, version))) {
+ if ((entry = a_Dicache_get_entry(Url, version))) {
++entry->RefCount;
}
return entry;
@@ -236,7 +240,8 @@ DICacheEntry* a_Dicache_ref(const DilloUrl *Url, int version)
/*
* Invalidate this entry. This is used for the reloading mechanism.
- * Can't erase current versions, but a_Dicache_get_entry must return NULL.
+ * Can't erase current versions, but a_Dicache_get_entry(url, DIC_Last)
+ * must return NULL.
*/
void a_Dicache_invalidate_entry(const DilloUrl *Url)
{
@@ -251,57 +256,6 @@ void a_Dicache_invalidate_entry(const DilloUrl *Url)
/* ------------------------------------------------------------------------- */
/*
- * This function is a cache client; (but feeds its clients from dicache)
- */
-void a_Dicache_callback(int Op, CacheClient_t *Client)
-{
- /* TODO: Handle Op = CA_Abort (to show what was got) --Jcid */
- uint_t i;
- DilloWeb *Web = Client->Web;
- DilloImage *Image = Web->Image;
- DICacheEntry *DicEntry = a_Dicache_get_entry(Web->url);
-
- dReturn_if_fail ( DicEntry != NULL );
-
- /* when the data stream is not an image 'v_imgbuf' remains NULL */
- if (Op == CA_Send && DicEntry->v_imgbuf) {
- if (Image->height == 0 && DicEntry->State >= DIC_SetParms) {
- /* Set parms */
- a_Image_set_parms(
- Image, DicEntry->v_imgbuf, DicEntry->url,
- DicEntry->version, DicEntry->width, DicEntry->height,
- DicEntry->type);
- }
- if (DicEntry->State == DIC_Write) {
- if (DicEntry->ScanNumber == Image->ScanNumber) {
- for (i = 0; i < DicEntry->height; ++i)
- if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) &&
- !a_Bitvec_get_bit(Image->BitVec, (int)i) )
- a_Image_write(Image, DicEntry->v_imgbuf,
- DicEntry->linebuf, i, FALSE);
- } else {
- for (i = 0; i < DicEntry->height; ++i) {
- if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) ||
- !a_Bitvec_get_bit(Image->BitVec, (int)i) ||
- DicEntry->ScanNumber > Image->ScanNumber + 1) {
- a_Image_write(Image, DicEntry->v_imgbuf,
- DicEntry->linebuf, i, FALSE);
- }
- if (!a_Bitvec_get_bit(DicEntry->BitVec, (int)i))
- a_Bitvec_clear_bit(Image->BitVec, (int)i);
- }
- Image->ScanNumber = DicEntry->ScanNumber;
- }
- }
- } else if (Op == CA_Close || Op == CA_Abort) {
- a_Image_close(Web->Image);
- a_Bw_close_client(Web->bw, Client->Key);
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-/*
* Set image's width, height & type
* (By now, we'll use the image information despite the html tags --Jcid)
*/
@@ -309,37 +263,29 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
uint_t width, uint_t height, DilloImgType type)
{
DICacheEntry *DicEntry;
- size_t Size = width * height * 3;
+ _MSG("a_Dicache_set_parms (%s)\n", URL_STR(url));
dReturn_if_fail ( Image != NULL && width && height );
/* Find the DicEntry for this Image */
- DicEntry = Dicache_get_entry_version(url, version);
+ DicEntry = a_Dicache_get_entry(url, version);
dReturn_if_fail ( DicEntry != NULL );
+ /* Parameters already set? */
+ dReturn_if_fail ( DicEntry->State < DIC_SetParms );
- /* Initialize the DicEntry */
- DicEntry->linebuf = dNew(uchar_t, width * 3);
- dReturn_if_fail ( DicEntry->linebuf != NULL );
+ _MSG(" RefCount=%d version=%d\n", DicEntry->RefCount, DicEntry->version);
/* BUG: there's just one image-type now */
#define I_RGB 0
- DicEntry->v_imgbuf = a_Image_imgbuf_new(Image->dw, I_RGB, width, height);
+ DicEntry->v_imgbuf = a_Imgbuf_new(Image->dw, I_RGB, width, height);
- /* This extra reference activates the dicache ALWAYS.
- * Extra code is necessary in Imgbuf to be able to free it */
- //a_Image_imgbuf_ref(DicEntry->v_imgbuf);
-
- DicEntry->TotalSize = Size;
+ DicEntry->TotalSize = width * height * 3;
DicEntry->width = width;
DicEntry->height = height;
DicEntry->type = type;
DicEntry->BitVec = a_Bitvec_new((int)height);
DicEntry->State = DIC_SetParms;
- dicache_size_total += Size;
-
- /* Allocate and initialize this image */
- a_Image_set_parms(Image, DicEntry->v_imgbuf, url, version,
- width, height, type);
+ dicache_size_total += DicEntry->TotalSize;
}
/*
@@ -349,8 +295,9 @@ void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
const uchar_t *cmap, uint_t num_colors,
int num_colors_max, int bg_index)
{
- DICacheEntry *DicEntry = Dicache_get_entry_version(url, version);
+ DICacheEntry *DicEntry = a_Dicache_get_entry(url, version);
+ _MSG("a_Dicache_set_cmap\n");
dReturn_if_fail ( DicEntry != NULL );
dFree(DicEntry->cmap);
@@ -362,24 +309,27 @@ void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
DicEntry->cmap[bg_index * 3 + 2] = (Image->bg_color) & 0xff;
}
- a_Image_set_cmap(Image, DicEntry->cmap);
DicEntry->State = DIC_SetCmap;
}
/*
* Reset for a new scan from a multiple-scan image.
*/
-void a_Dicache_new_scan(DilloImage *image, const DilloUrl *url, int version)
+void a_Dicache_new_scan(const DilloUrl *url, int version)
{
DICacheEntry *DicEntry;
+ _MSG("a_Dicache_new_scan\n");
dReturn_if_fail ( url != NULL );
- DicEntry = Dicache_get_entry_version(url, version);
+ DicEntry = a_Dicache_get_entry(url, version);
dReturn_if_fail ( DicEntry != NULL );
-
+ if (DicEntry->State < DIC_SetParms) {
+ MSG("a_Dicache_new_scan before DIC_SetParms\n");
+ exit(1);
+ }
a_Bitvec_clear(DicEntry->BitVec);
DicEntry->ScanNumber++;
- a_Image_new_scan(image, DicEntry->v_imgbuf);
+ a_Imgbuf_new_scan(DicEntry->v_imgbuf);
}
/*
@@ -388,18 +338,19 @@ void a_Dicache_new_scan(DilloImage *image, const DilloUrl *url, int version)
* buf: row buffer
* Y : row number
*/
-void a_Dicache_write(DilloImage *Image, DilloUrl *url, int version,
- const uchar_t *buf, uint_t Y)
+void a_Dicache_write(DilloUrl *url, int version, const uchar_t *buf, uint_t Y)
{
DICacheEntry *DicEntry;
- dReturn_if_fail ( Image != NULL );
- DicEntry = Dicache_get_entry_version(url, version);
+ _MSG("a_Dicache_write\n");
+ DicEntry = a_Dicache_get_entry(url, version);
dReturn_if_fail ( DicEntry != NULL );
dReturn_if_fail ( DicEntry->width > 0 && DicEntry->height > 0 );
- a_Image_write(Image, DicEntry->v_imgbuf, buf, Y, TRUE);
- DicEntry->Y = Y;
+ /* update the common buffer in the imgbuf */
+ a_Imgbuf_update(DicEntry->v_imgbuf, buf, DicEntry->type,
+ DicEntry->cmap, DicEntry->width, DicEntry->height, Y);
+
a_Bitvec_set_bit(DicEntry->BitVec, (int)Y);
DicEntry->State = DIC_Write;
}
@@ -410,19 +361,169 @@ void a_Dicache_write(DilloImage *Image, DilloUrl *url, int version,
void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
{
DilloWeb *Web = Client->Web;
- DICacheEntry *DicEntry = Dicache_get_entry_version(url, version);
+ DICacheEntry *DicEntry = a_Dicache_get_entry(url, version);
dReturn_if_fail ( DicEntry != NULL );
- DicEntry->State = DIC_Close;
- dFree(DicEntry->cmap);
- DicEntry->cmap = NULL;
- dFree(DicEntry->linebuf);
- DicEntry->linebuf = NULL;
- a_Image_close(Web->Image);
+ /* a_Dicache_unref() may free DicEntry */
+ _MSG("a_Dicache_close RefCount=%d\n", DicEntry->RefCount - 1);
+
+ if (DicEntry->State < DIC_Close) {
+ DicEntry->State = DIC_Close;
+ dFree(DicEntry->cmap);
+ DicEntry->cmap = NULL;
+ DicEntry->Decoder = NULL;
+ DicEntry->DecoderData = NULL;
+ }
+ a_Dicache_unref(url, version);
+
a_Bw_close_client(Web->bw, Client->Key);
}
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Generic MIME handler for GIF, JPEG and PNG.
+ * Sets a_Dicache_callback as the cache-client,
+ * and also sets the image decoder.
+ *
+ * Parameters:
+ * Type: MIME type
+ * Ptr: points to a Web structure
+ * Call: Dillo calls this with more data/eod
+ * Data: Decoding data structure
+ */
+static void *Dicache_image(int ImgType, const char *MimeType, void *Ptr,
+ CA_Callback_t *Call, void **Data)
+{
+ DilloWeb *web = Ptr;
+ DICacheEntry *DicEntry;
+
+ dReturn_val_if_fail(MimeType && Ptr, NULL);
+
+ if (!web->Image) {
+ web->Image = a_Image_new(NULL, web->bgColor);
+ a_Image_ref(web->Image);
+ }
+
+ DicEntry = a_Dicache_get_entry(web->url, DIC_Last);
+ if (!DicEntry) {
+ /* Let's create an entry for this image... */
+ DicEntry = Dicache_add_entry(web->url);
+ DicEntry->DecoderData =
+ (ImgType == DIC_Png) ?
+ a_Png_new(web->Image, DicEntry->url, DicEntry->version) :
+ (ImgType == DIC_Gif) ?
+ a_Gif_new(web->Image, DicEntry->url, DicEntry->version) :
+ (ImgType == DIC_Jpeg) ?
+ a_Jpeg_new(web->Image, DicEntry->url, DicEntry->version) :
+ NULL;
+ } else {
+ /* Repeated image */
+ a_Dicache_ref(DicEntry->url, DicEntry->version);
+ }
+ DicEntry->Decoder = (ImgType == DIC_Png) ? (CA_Callback_t)a_Png_callback :
+ (ImgType == DIC_Gif) ? (CA_Callback_t)a_Gif_callback :
+ (ImgType == DIC_Jpeg) ? (CA_Callback_t)a_Jpeg_callback:
+ NULL;
+ *Data = DicEntry->DecoderData;
+ *Call = (CA_Callback_t) a_Dicache_callback;
+
+ return (web->Image->dw);
+}
+
+/*
+ * PNG wrapper for Dicache_image()
+ */
+void *a_Dicache_png_image(const char *Type, void *Ptr, CA_Callback_t *Call,
+ void **Data)
+{
+ return Dicache_image(DIC_Png, Type, Ptr, Call, Data);
+}
+
+/*
+ * GIF wrapper for Dicache_image()
+ */
+void *a_Dicache_gif_image(const char *Type, void *Ptr, CA_Callback_t *Call,
+ void **Data)
+{
+ return Dicache_image(DIC_Gif, Type, Ptr, Call, Data);
+}
+
+/*
+ * JPEG wrapper for Dicache_image()
+ */
+void *a_Dicache_jpeg_image(const char *Type, void *Ptr, CA_Callback_t *Call,
+ void **Data)
+{
+ return Dicache_image(DIC_Jpeg, Type, Ptr, Call, Data);
+}
+
+/*
+ * This function is a cache client; (but feeds its clients from dicache)
+ */
+void a_Dicache_callback(int Op, CacheClient_t *Client)
+{
+ uint_t i;
+ DilloWeb *Web = Client->Web;
+ DilloImage *Image = Web->Image;
+ DICacheEntry *DicEntry = a_Dicache_get_entry(Web->url, DIC_Last);
+
+ dReturn_if_fail ( DicEntry != NULL );
+
+ /* Copy the version number in the Client */
+ if (Client->Version == 0)
+ Client->Version = DicEntry->version;
+
+ /* Only call the decoder when necessary */
+ if (Op == CA_Send && DicEntry->State < DIC_Close &&
+ DicEntry->DecodedSize < Client->BufSize) {
+ DicEntry->Decoder(Op, Client);
+ DicEntry->DecodedSize = Client->BufSize;
+ } else if (Op == CA_Close || Op == CA_Abort) {
+ if (DicEntry->State < DIC_Close) {
+ DicEntry->Decoder(Op, Client);
+ } else {
+ a_Dicache_close(DicEntry->url, DicEntry->version, Client);
+ }
+ }
+
+ /* when the data stream is not an image 'v_imgbuf' remains NULL */
+ if (Op == CA_Send && DicEntry->v_imgbuf) {
+ if (Image->height == 0 && DicEntry->State >= DIC_SetParms) {
+ /* Set parms */
+ a_Image_set_parms(
+ Image, DicEntry->v_imgbuf, DicEntry->url,
+ DicEntry->version, DicEntry->width, DicEntry->height,
+ DicEntry->type);
+ }
+ if (DicEntry->State == DIC_Write) {
+ if (DicEntry->ScanNumber == Image->ScanNumber) {
+ for (i = 0; i < DicEntry->height; ++i)
+ if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) &&
+ !a_Bitvec_get_bit(Image->BitVec, (int)i) )
+ a_Image_write(Image, i);
+ } else {
+ for (i = 0; i < DicEntry->height; ++i) {
+ if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) ||
+ !a_Bitvec_get_bit(Image->BitVec, (int)i) ||
+ DicEntry->ScanNumber > Image->ScanNumber + 1) {
+ a_Image_write(Image, i);
+ }
+ if (!a_Bitvec_get_bit(DicEntry->BitVec, (int)i))
+ a_Bitvec_clear_bit(Image->BitVec, (int)i);
+ }
+ Image->ScanNumber = DicEntry->ScanNumber;
+ }
+ }
+ } else if (Op == CA_Close || Op == CA_Abort) {
+ a_Image_close(Image);
+ a_Bw_close_client(Web->bw, Client->Key);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
/*
* Free the imgbuf (RGB data) of unused entries.
*/
@@ -432,12 +533,13 @@ void a_Dicache_cleanup(void)
DICacheNode *node;
DICacheEntry *entry;
+ _MSG("a_Dicache_cleanup\n");
for (i = 0; i < dList_length(CachedIMGs); ++i) {
node = dList_nth_data(CachedIMGs, i);
/* iterate each entry of this node */
for (entry = node->first; entry; entry = entry->next) {
if (entry->v_imgbuf &&
- a_Image_imgbuf_last_reference(entry->v_imgbuf)) {
+ a_Imgbuf_last_reference(entry->v_imgbuf)) {
/* free this unused entry */
if (entry->next) {
Dicache_remove(node->url, entry->version);
@@ -467,12 +569,11 @@ void a_Dicache_freeall(void)
while ((entry = node->first)) {
node->first = entry->next;
dFree(entry->cmap);
- dFree(entry->linebuf);
a_Bitvec_free(entry->BitVec);
- a_Image_imgbuf_unref(entry->v_imgbuf);
+ a_Imgbuf_unref(entry->v_imgbuf);
dicache_size_total -= entry->TotalSize;
}
- dList_remove(CachedIMGs, node);
+ dList_remove_fast(CachedIMGs, node);
a_Url_free(node->url);
dFree(node);
}