summaryrefslogtreecommitdiff
path: root/src/dicache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dicache.c')
-rw-r--r--src/dicache.c272
1 files changed, 117 insertions, 155 deletions
diff --git a/src/dicache.c b/src/dicache.c
index db3b86b2..a2904c32 100644
--- a/src/dicache.c
+++ b/src/dicache.c
@@ -28,15 +28,10 @@ enum {
DIC_Jpeg
};
-typedef struct {
- int valid; /* flag */
- DilloUrl *url; /* primary "Key" for this dicache entry */
- DICacheEntry *first; /* pointer to the first dicache entry in this list */
-} DICacheNode;
/*
- * List of DICacheNode. One node per URL. Each node may have several
- * versions of the same image in a linked list.
+ * List of DICacheEntry. May hold several versions of the same image,
+ * although most of the time it holds just one.
*/
static Dlist *CachedIMGs = NULL;
@@ -45,24 +40,20 @@ static uint_t dicache_size_total; /* invariant: dicache_size_total is
* of all the images in the dicache. */
/*
- * Compare two dicache nodes
+ * Compare function for image entries
*/
-static int Dicache_node_cmp(const void *v1, const void *v2)
+static int Dicache_entry_cmp(const void *v1, const void *v2)
{
- const DICacheNode *n1 = v1, *n2 = v2;
-
- return a_Url_cmp(n1->url, n2->url);
-}
-
-/*
- * Compare function for searching a node by Url
- */
-static int Dicache_node_by_url_cmp(const void *v1, const void *v2)
-{
- const DICacheNode *node = v1;
- const DilloUrl *url = v2;
-
- return a_Url_cmp(node->url, url);
+ const DICacheEntry *e1 = v1, *e2 = v2;
+
+ int st = a_Url_cmp(e1->url, e2->url);
+ if (st == 0) {
+ if (e2->version == DIC_Last)
+ st = (e1->Flags & DIF_Last ? 0 : -1);
+ else
+ st = (e1->version - e2->version);
+ }
+ return st;
}
/*
@@ -83,6 +74,8 @@ static DICacheEntry *Dicache_entry_new(void)
entry->width = 0;
entry->height = 0;
+ entry->Flags = DIF_Valid;
+ entry->SurvCleanup = 0;
entry->type = DILLO_IMG_TYPE_NOTSET;
entry->cmap = NULL;
entry->v_imgbuf = NULL;
@@ -97,41 +90,29 @@ static DICacheEntry *Dicache_entry_new(void)
entry->DecoderData = NULL;
entry->DecodedSize = 0;
- entry->next = NULL;
-
return entry;
}
/*
* Add a new entry in the dicache
- * (a single node (URL) may have several entries)
+ * (a single URL may have several entries)
*/
static DICacheEntry *Dicache_add_entry(const DilloUrl *Url)
{
- DICacheEntry *entry;
- DICacheNode *node;
+ DICacheEntry e, *entry, *last;
entry = Dicache_entry_new();
-
- if ((node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp))) {
- /* this URL is already in CachedIMGs, add entry at the END of the list */
- DICacheEntry *ptr = node->first;
-
- node->valid = 1;
- for ( ; ptr->next; ptr = ptr->next);
- ptr->next = entry;
- entry->version = ptr->version+1;
- entry->url = node->url;
-
- } else { /* no node yet, so create one */
- DICacheNode *node = dNew(DICacheNode, 1);
-
- node->url = a_Url_dup(Url);
- entry->url = node->url;
- node->first = entry;
- node->valid = 1;
- dList_insert_sorted(CachedIMGs, node, Dicache_node_cmp);
+ e.url = (DilloUrl*)Url;
+ e.version = DIC_Last;
+ last = dList_find_sorted(CachedIMGs, &e, Dicache_entry_cmp);
+ if (last) {
+ /* URL is already in CachedIMGs, make a new version */
+ last->Flags &= ~DIF_Last;
+ entry->version = last->version + 1;
}
+ entry->url = a_Url_dup(Url);
+ entry->Flags |= DIF_Last;
+ dList_insert_sorted(CachedIMGs, entry, Dicache_entry_cmp);
return entry;
}
@@ -145,23 +126,15 @@ static DICacheEntry *Dicache_add_entry(const DilloUrl *Url)
*/
DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version)
{
- DICacheNode *node;
+ DICacheEntry e;
DICacheEntry *entry = NULL;
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) ;
- }
- }
+ e.url = (DilloUrl*)Url;
+ e.version = version;
+ entry = dList_find_sorted(CachedIMGs, &e, Dicache_entry_cmp);
+ if (entry && !(entry->Flags & DIF_Valid) && version == DIC_Last)
+ entry = NULL;
return entry;
}
@@ -170,57 +143,48 @@ DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version)
*/
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;
+ DICacheEntry e, *entry;
- while (entry && (entry->version != version) ) {
- prev = entry;
- entry = entry->next;
- }
-
- if (entry) {
- _MSG("Dicache_remove Decoder=%p DecoderData=%p\n",
- entry->Decoder, entry->DecoderData);
- /* Eliminate this dicache entry */
- dFree(entry->cmap);
- a_Bitvec_free(entry->BitVec);
- a_Imgbuf_unref(entry->v_imgbuf);
- if (entry->Decoder) {
- entry->Decoder(CA_Abort, entry->DecoderData);
- }
- dicache_size_total -= entry->TotalSize;
-
- if (node->first == entry) {
- if (!entry->next) {
- /* last entry with this URL. Remove the node as well */
- dList_remove(CachedIMGs, node);
- a_Url_free(node->url);
- dFree(node);
- } else
- node->first = entry->next;
- } else {
- prev->next = entry->next;
- }
- dFree(entry);
+ _MSG("Dicache_remove url=%s\n", URL_STR(Url));
+ e.url = (DilloUrl*)Url;
+ e.version = version;
+ entry = dList_find_sorted(CachedIMGs, &e, Dicache_entry_cmp);
+ dReturn_if (entry == NULL);
+
+ _MSG("Dicache_remove Imgbuf=%p Decoder=%p DecoderData=%p\n",
+ entry->v_imgbuf, entry->Decoder, entry->DecoderData);
+ /* Eliminate this dicache entry */
+ dList_remove(CachedIMGs, entry);
+ dicache_size_total -= entry->TotalSize;
+
+ /* entry cleanup */
+ a_Url_free(entry->url);
+ dFree(entry->cmap);
+ a_Bitvec_free(entry->BitVec);
+ a_Imgbuf_unref(entry->v_imgbuf);
+ if (entry->Decoder) {
+ entry->Decoder(CA_Abort, entry->DecoderData);
}
+ dFree(entry);
}
/*
- * Unrefs the counter of a dicache entry, and _if_ no DwImage is acessing
- * this buffer, then we call Dicache_remove() to do the job.
+ * Unrefs the counter of a dicache entry (it counts cache clients).
+ * If there're no clients and no imgbuf, remove the entry.
+ * Otherwise, let a_Dicache_cleanup() do the job later
+ * (keeping it cached meanwhile for e.g. reload, repush, back/fwd).
*/
void a_Dicache_unref(const DilloUrl *Url, int version)
{
DICacheEntry *entry;
- _MSG("a_Dicache_unref\n");
if ((entry = a_Dicache_get_entry(Url, version))) {
- if (--entry->RefCount == 0) {
+ _MSG("a_Dicache_unref: RefCount=%d State=%d ImgbufLastRef=%d\n",
+ entry->RefCount, entry->State,
+ entry->v_imgbuf ? a_Imgbuf_last_reference(entry->v_imgbuf) : -1);
+ if (entry->RefCount > 0) --entry->RefCount;
+ if (entry->RefCount == 0 && entry->v_imgbuf == NULL)
Dicache_remove(Url, version);
- }
}
}
@@ -244,11 +208,9 @@ DICacheEntry* a_Dicache_ref(const DilloUrl *Url, int version)
*/
void a_Dicache_invalidate_entry(const DilloUrl *Url)
{
- DICacheNode *node;
-
- node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
- if (node)
- node->valid = 0;
+ DICacheEntry *entry = a_Dicache_get_entry(Url, DIC_Last);
+ if (entry)
+ entry->Flags &= ~DIF_Valid;
}
@@ -256,7 +218,9 @@ void a_Dicache_invalidate_entry(const DilloUrl *Url)
/*
* Set image's width, height & type
- * (By now, we'll use the image information despite the html tags --Jcid)
+ * - 'width' and 'height' come from the image data.
+ * - HTML width and height attrs are handled with setNonCssHint.
+ * - CSS sizing is handled by the CSS engine.
*/
void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
uint_t width, uint_t height, DilloImgType type,
@@ -269,7 +233,7 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
/* Find the DicEntry for this Image */
DicEntry = a_Dicache_get_entry(url, version);
dReturn_if_fail ( DicEntry != NULL );
- /* Parameters already set? */
+ /* Parameters already set? Don't do it twice. */
dReturn_if_fail ( DicEntry->State < DIC_SetParms );
_MSG(" RefCount=%d version=%d\n", DicEntry->RefCount, DicEntry->version);
@@ -292,7 +256,7 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
/*
* Implement the set_cmap method for the Image
*/
-void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
+void a_Dicache_set_cmap(DilloUrl *url, int version, int bg_color,
const uchar_t *cmap, uint_t num_colors,
int num_colors_max, int bg_index)
{
@@ -305,9 +269,9 @@ void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
DicEntry->cmap = dNew0(uchar_t, 3 * num_colors_max);
memcpy(DicEntry->cmap, cmap, 3 * num_colors);
if (bg_index >= 0 && (uint_t)bg_index < num_colors) {
- DicEntry->cmap[bg_index * 3] = (Image->bg_color >> 16) & 0xff;
- DicEntry->cmap[bg_index * 3 + 1] = (Image->bg_color >> 8) & 0xff;
- DicEntry->cmap[bg_index * 3 + 2] = (Image->bg_color) & 0xff;
+ DicEntry->cmap[bg_index * 3] = (bg_color >> 16) & 0xff;
+ DicEntry->cmap[bg_index * 3 + 1] = (bg_color >> 8) & 0xff;
+ DicEntry->cmap[bg_index * 3 + 2] = (bg_color) & 0xff;
}
DicEntry->State = DIC_SetCmap;
@@ -368,6 +332,9 @@ void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
/* a_Dicache_unref() may free DicEntry */
_MSG("a_Dicache_close RefCount=%d\n", DicEntry->RefCount - 1);
+ _MSG("a_Dicache_close DIC_Close=%d State=%d\n", DIC_Close, DicEntry->State);
+ _MSG(" a_Dicache_close imgbuf=%p Decoder=%p DecoderData=%p\n",
+ DicEntry->v_imgbuf, DicEntry->Decoder, DicEntry->DecoderData);
if (DicEntry->State < DIC_Close) {
DicEntry->State = DIC_Close;
@@ -410,24 +377,29 @@ static void *Dicache_image(int ImgType, const char *MimeType, void *Ptr,
DicEntry = a_Dicache_get_entry(web->url, DIC_Last);
if (!DicEntry) {
- /* Let's create an entry for this image... */
+ /* 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;
+ /* Attach a decoder */
+ if (ImgType == DIC_Jpeg) {
+ DicEntry->Decoder = (CA_Callback_t)a_Jpeg_callback;
+ DicEntry->DecoderData =
+ a_Jpeg_new(web->Image, DicEntry->url, DicEntry->version);
+ } else if (ImgType == DIC_Gif) {
+ DicEntry->Decoder = (CA_Callback_t)a_Gif_callback;
+ DicEntry->DecoderData =
+ a_Gif_new(web->Image, DicEntry->url, DicEntry->version);
+ } else if (ImgType == DIC_Png) {
+ DicEntry->Decoder = (CA_Callback_t)a_Png_callback;
+ DicEntry->DecoderData =
+ a_Png_new(web->Image, DicEntry->url, DicEntry->version);
+ }
} 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;
+ /* Survive three cleanup passes (set to zero = old behaviour). */
+ DicEntry->SurvCleanup = 3;
+
*Data = DicEntry->DecoderData;
*Call = (CA_Callback_t) a_Dicache_callback;
@@ -535,52 +507,42 @@ void a_Dicache_callback(int Op, CacheClient_t *Client)
void a_Dicache_cleanup(void)
{
int i;
- 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_Imgbuf_last_reference(entry->v_imgbuf)) {
- /* free this unused entry */
- if (entry->next) {
- Dicache_remove(node->url, entry->version);
- } else {
- Dicache_remove(node->url, entry->version);
- --i;
- break;
- }
- }
+ for (i = 0; (entry = dList_nth_data(CachedIMGs, i)); ++i) {
+ _MSG(" SurvCleanup = %d\n", entry->SurvCleanup);
+ if (entry->RefCount == 0 &&
+ (!entry->v_imgbuf || a_Imgbuf_last_reference(entry->v_imgbuf))) {
+ if (--entry->SurvCleanup >= 0)
+ continue; /* keep the entry one more pass */
+
+ /* free this unused entry */
+ Dicache_remove(entry->url, entry->version);
+ --i; /* adjust counter */
}
}
+ MSG("a_Dicache_cleanup: length = %d\n", dList_length(CachedIMGs));
}
/* ------------------------------------------------------------------------- */
/*
* Deallocate memory used by dicache module
- * (Call this one at exit time)
+ * (Call this one at exit time, with no cache clients queued)
*/
void a_Dicache_freeall(void)
{
- DICacheNode *node;
DICacheEntry *entry;
- /* Remove every dicache node and its entries */
- while ((node = dList_nth_data(CachedIMGs, 0))) {
- while ((entry = node->first)) {
- node->first = entry->next;
- dFree(entry->cmap);
- a_Bitvec_free(entry->BitVec);
- a_Imgbuf_unref(entry->v_imgbuf);
- dicache_size_total -= entry->TotalSize;
- }
- dList_remove_fast(CachedIMGs, node);
- a_Url_free(node->url);
- dFree(node);
+ /* Remove all the dicache entries */
+ while ((entry = dList_nth_data(CachedIMGs, dList_length(CachedIMGs)-1))) {
+ dList_remove_fast(CachedIMGs, entry);
+ a_Url_free(entry->url);
+ dFree(entry->cmap);
+ a_Bitvec_free(entry->BitVec);
+ a_Imgbuf_unref(entry->v_imgbuf);
+ dicache_size_total -= entry->TotalSize;
+ dFree(entry);
}
dList_free(CachedIMGs);
}