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