diff options
Diffstat (limited to 'src/dicache.c')
-rw-r--r-- | src/dicache.c | 375 |
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); } |