Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1555 lines
45 KiB

/*
Enhanced NCSA Mosaic from Spyglass
"Guitar"
Copyright 1994 Spyglass, Inc.
All Rights Reserved
Author(s):
Jim Seidman [email protected]
*/
#include "all.h"
#include "safestrm.h"
#include "decoder.h"
#include "blob.h"
// used to implement bNoImageCache - count of Image_Fetch_Async calls
static unsigned long gcbImgLoadCount = 1;
static far struct hash_table gImageCache;
static unsigned int gTotalCached = 0;
static unsigned int gTotalAvailable = 0;
static BOOL Image_Nuke(struct _www *w3doc,int cbElement,BOOL bNukeMaps, BOOL bNukeDCache);
static void Image_Swap(struct _www *w3doc,struct ImageInfo *pOld,struct ImageInfo *pNew);
static void Image_Revert(struct ImageInfo *pOld);
static void x_DisposeImage(struct ImageInfo *img, BOOL bFreeImg)
{
if (img->hPalette)
DeleteObject(img->hPalette);
if (img->data)
{
int cbBytesPer = ((wg.eColorMode != 8) && (wg.eColorMode != 4) && img->flags & IMG_JPEG) ? 3 : 1;
gTotalCached -= img->width*img->height*cbBytesPer;
GTR_FREE(img->data);
}
if (img->pbmi)
{
GTR_FREE(img->pbmi);
}
if (img->srcURL && bFreeImg)
{
GTR_FREE(img->srcURL);
}
if (img->actualURL && img->actualURL != img->srcURL)
{
GTR_FREE(img->actualURL);
}
if (bFreeImg)
{
if (img->pImgOtherVers) img->pImgOtherVers->pImgOtherVers = NULL;
GTR_FREE(img);
}
else
{
img->hPalette = NULL;
img->data = NULL;
img->pbmi = NULL;
img->actualURL = img->srcURL;
}
}
/* Reduce the amount of memory used by images. If nWanted < 0, gTotalCached
* is ignored and all possible memory is freed, otherwise nWanted is ignored.
* BOOL fNoW3Docs: if TRUE, then we free only the images that currently
* have a zero ref. count (used by dcache code)
* if FALSE, then we are allowed to free w3doc's and then
* free more images that will have a zero refcount as a
* result of the freeing up of w3docs.
*
*/
extern BOOL Image_ReduceMemory(int nWanted, BOOL fOKToDelW3Docs)
{
struct ImageInfo *img;
int ndx;
int count;
BOOL bStillTrying = TRUE;
BOOL bDidFree = FALSE;
DWORD totalAvailable = (nWanted < 0 ? 0 : gTotalAvailable);
while (bStillTrying)
{
if (gTotalCached > totalAvailable)
{
count = Hash_Count(&gImageCache);
for (ndx = count-1; ndx >= 0; ndx--)
{
Hash_GetIndexedEntry(&gImageCache, ndx, NULL, NULL, (void **) &img);
if (!img->refCount)
{
XX_DMsg(DBG_IMAGE, ("Deleting entry %d from the image cache\n", ndx));
/* If this is merely a placeholder, there may not be any image to delete */
x_DisposeImage(img, TRUE);
Hash_DeleteIndexedEntry(&gImageCache, ndx);
bDidFree = TRUE;
if (gTotalCached > totalAvailable)
{
bStillTrying = FALSE;
break;
}
}
}
bStillTrying = ( fOKToDelW3Docs
&& W3Doc_ReduceMemory(1, NULL));
} else bStillTrying = FALSE;
}
#ifdef XX_DEBUG
if (gTotalCached >= gTotalAvailable)
{
/* The cache is now overfull */
XX_DMsg(DBG_IMAGE, ("Need to delete an image from the cache, but cannot\n"));
}
#endif
return bDidFree;
}
static void Image_InitHash(void)
{
static BOOL bInitialized = FALSE;
MEMORYSTATUS memStatus;
int denominator;
if (!bInitialized)
{
Hash_Init(&gImageCache);
#ifdef USE_MEMMANAGE
/* We give it a small initial value but a big increment, since after
the first call we won't be able to free any more unless some
documents get freed too. */
GTR_RegisterMemoryReducer(Image_ReduceMemory, 1.0f, 10.0f, TRUE);
#endif
// guard against rediculously large cache fraction
denominator = gPrefs.image_cache_size;
if (denominator < 4) denominator = 4;
bInitialized = TRUE;
memStatus.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&memStatus);
gTotalAvailable = memStatus.dwTotalPhys / denominator;
if (gTotalAvailable + MINIMUM_DELTAPRINT > memStatus.dwAvailPageFile)
{
gTotalAvailable = memStatus.dwAvailPageFile < MINIMUM_DELTAPRINT ? 0 : memStatus.dwAvailPageFile - MINIMUM_DELTAPRINT;
}
}
}
static int Image_AddToCache(const char *url, struct ImageInfo *myImage)
{
return Hash_Add(&gImageCache, url, NULL, (void *) myImage);
}
void Image_NukeRef(struct ImageInfo *pImg)
{
struct ImageInfo *pHashImg;
pImg->refCount--;
if (pImg->refCount == 0)
{
Hash_Find(&gImageCache, pImg->srcURL, NULL, (void **) &pHashImg);
if (pHashImg != pImg) // Is it a stale version?
{
// DEEPAK: here you blast pImg from aux cache
/* What if it isn't in the aux cache? Is it expected to be there?
* I saw a case where it wasn't in the aux cache
*/
DeleteAuxEntry(pImg);
XX_DMsg(DBG_IMAGE, ("freeing stale image %s\n",pImg->srcURL));
x_DisposeImage(pImg, TRUE);
}
}
}
void Image_AddRef(struct ImageInfo *pImg)
{
pImg->refCount++;
}
/*
The HTGIF and HTXBM classes call this function when a complete image
has been received.
*/
void Image_SetImageData(const char *srcURL, const char *actualURL, unsigned char *data, int width, int height, HPALETTE hPalette, long transparent, unsigned int flags,unsigned long cbCheckSum)
{
struct ImageInfo *pImg;
XX_DMsg(DBG_IMAGE, ("Image_SetImageData: Called for %s (%s) (w = %d, h =%d)\n", srcURL,(actualURL ? actualURL:""), width, height));
/* Find the entry for this image in the cache */
pImg = NULL;
Hash_Find(&gImageCache, srcURL, NULL, (void **) &pImg);
if (!pImg)
{
XX_DMsg(DBG_IMAGE, ("Image_SetImageData: No image placeholder exists for '%s'\n", srcURL));
return;
}
#ifdef XX_DEBUG
/* See whether the image's actual width and height match the placeholder's */
if (pImg->width && (pImg->width != width || pImg->height != height))
{
XX_DMsg(DBG_IMAGE, ("Image_SetImageData: size mismatch for '%s'\n\t\told size = (%d,%d), new = (%d,%d)\n",
srcURL, pImg->width, pImg->height, width, height));
}
#endif
x_DisposeImage(pImg, FALSE);
pImg->cbCheckSum = cbCheckSum;
if (width == 0)
{
/* OK, this is a hack where height now contains error flags. */
if (height)
pImg->flags = height;
else
pImg->flags = IMG_ERROR;
pImg->width = 0;
pImg->height = 0;
#ifdef WIN32
pImg->data = NULL;
pImg->hPalette = NULL;
pImg->transparent = -1;
#endif
#ifdef MAC
pImg->gw = NULL;
#endif
#ifdef UNIX
pImg->data = NULL;
pImg->xPalette = NULL;
pImg->depth = 0;
pImg->xpix = 0;
pImg->transparent = -1;
#endif
}
else
{
pImg->width = width;
pImg->height = height;
#ifdef WIN32
if (data)
{
int cbBytesPer = ((wg.eColorMode != 8) && (wg.eColorMode != 4) && flags & IMG_JPEG) ? 3 : 1;
gTotalCached += width*height*cbBytesPer;
}
pImg->data = data;
pImg->hPalette = hPalette;
pImg->transparent = transparent;
pImg->flags = flags;
Image_ReduceMemory(0, /*fOKToDelW3Docs=*/TRUE);
XX_DMsg(DBG_IMAGE, ("total cached = %d\n",gTotalCached));
#endif
#ifdef MAC
pImg->gw = gw;
pImg->flags = 0;
#endif
#ifdef UNIX
pImg->data = data;
pImg->xPalette = xPalette;
pImg->depth = depth;
pImg->transparent = transparent;
pImg->flags = 0;
#endif
}
if (actualURL && strcmp(actualURL,srcURL)) pImg->actualURL = GTR_strdup(actualURL);
}
void *Image_GetDecoder(const char *srcURL)
{
struct ImageInfo *pImg;
/* Find the entry for this image in the cache */
pImg = NULL;
Hash_Find(&gImageCache, srcURL, NULL, (void **) &pImg);
return pImg ? pImg->decoderObject:NULL;
}
struct ImageInfo *Image_CreatePlaceholder(const char *full_address, int width, int height)
{
struct ImageInfo *myImage;
Image_InitHash();
/*
Check to see if it's in the cache
*/
myImage = NULL;
if (full_address) Hash_Find(&gImageCache, full_address, NULL, (void **) &myImage);
if (myImage)
{
if (width && height)
{
if (!myImage->width)
{
myImage->width = width;
myImage->height = height;
}
#ifdef XX_DEBUG
else
{
if (myImage->width != width)
XX_DMsg(DBG_IMAGE, ("Width mismatch on %s: hint=%d, previous=%d\n",myImage->srcURL, width, myImage->width));
if (myImage->height != height)
XX_DMsg(DBG_IMAGE, ("Height mismatch on %s: hint=%d, previous=%d\n", myImage->srcURL, height, myImage->height));
}
#endif
}
}
else
{
myImage = (struct ImageInfo *) GTR_MALLOC(sizeof(struct ImageInfo));
memset(myImage, 0, sizeof(struct ImageInfo));
myImage->flags = IMG_NOTLOADED;
if (!gPrefs.bAutoLoadImages)
myImage->flags |= IMG_LOADSUP;
myImage->width = width;
myImage->height = height;
if (width && height) myImage->flags |= IMG_WHKNOWN;
if (full_address){
Image_AddToCache(full_address, myImage);
myImage->srcURL = GTR_strdup(full_address);
}
myImage->actualURL = myImage->srcURL;
return myImage;
}
return myImage;
}
// FilterProc for the unblock conditionally on master blocked for reap
static boolean MasterFilter(ThreadID theThread,void *context)
{
struct Mwin *tw = Async_GetWindowFromThread(theThread);
if (tw == context)
{
if (TW_GETBLOCKED(tw,TW_REAPBLOCKED))
{
TW_CLEARBLOCKED(tw,TW_REAPBLOCKED);
return TRUE;
}
else if (TW_GETBLOCKED(tw,TW_VISBLOCKED))
{
TW_CLEARBLOCKED(tw,TW_VISBLOCKED);
return TRUE;
}
}
return FALSE;
}
/* Does a free of a ref counted object, suitable for sharing between async
threads. object is only freed when last accessor frees.
*/
void *pSafeFree(void *pSafeObject)
{
PSAFERESULT pResult = pSafeObject;
if (pResult != NULL)
{
if (--pResult->refcnt < 0)
{
GTR_FREE(pResult);
pResult = NULL;
}
}
return pResult;
}
/* returns TRUE iff there exists another accessor besides caller.
*/
INLINE BOOL bExistsAnother(void *pSafeObject)
{
PSAFERESULT pResult = pSafeObject;
return (pResult == NULL || pResult->refcnt == 0) ? FALSE : TRUE;
}
static void Nuke_Request(HTRequest *request)
{
request->referer = NULL;
if (request->szLocalFileName)
{
GTR_FREE(request->szLocalFileName);
request->szLocalFileName = NULL;
}
Dest_DestroyDest(request->destination);
request->destination = NULL;
HTRequest_delete(request);
}
INLINE struct ImageInfo *pImgLookup(struct Mwin *twDoc,int nEl)
{
return (twDoc->w3doc == NULL ? NULL : twDoc->w3doc->aElements[nEl].myImage);
}
struct Params_Image_Load
{
HTRequest * request; /* Request to use to load image */
PSAFERESULT pStatus; /* used to pass back status across threads */
void *decoderObject; /* Decoder reserved for fetch */
unsigned long cbRequestID; /* uniquely identifies operation & decoder */
struct Mwin *twDoc; /* window defining w3doc w/ img */
int nEl; /* Which element we're on */
ThreadID parentThread; /* thread id of parent to unblock */
};
#define STATE_LOAD_TRIEDLOAD (STATE_OTHER)
int Image_Load_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_Load *pParams;
struct Params_LoadAsync *pLoadParams;
struct ImageInfo *pImg;
pParams = *ppInfo;
switch (nState)
{
case STATE_INIT:
pParams->request = HTRequest_validate(pParams->request);
if (pParams->request == NULL || tw == NULL) return STATE_ABORT;
pImg = pImgLookup(pParams->twDoc,pParams->nEl);
XX_DMsg(DBG_IMAGE, ("Image_Load_Async: Called for %s\n", pImg ?pImg->srcURL:"DEAD IMAGE"));
{
pLoadParams = GTR_MALLOC(sizeof(*pLoadParams));
if (pLoadParams == NULL) return STATE_ABORT;
pLoadParams->request = pParams->request;
pLoadParams->pStatus = &(pParams->pStatus->status);
pLoadParams->fLoadFromDCacheOK = FALSE;
Async_DoCall(HTLoadDocument_Async, pLoadParams);
}
return STATE_LOAD_TRIEDLOAD;
case STATE_LOAD_TRIEDLOAD:
case STATE_ABORT:
/* Need to deal with possibility that decoder has been shot out from under */
pParams->request = HTRequest_validate(pParams->request);
if (tw)
{
pImg = pImgLookup(pParams->twDoc,pParams->nEl);
if (pImg &&
pParams->decoderObject == pImg->decoderObject &&
cbDC_GetRequestID(pParams->decoderObject) == pParams->cbRequestID &&
cbDC_GetStatus(pParams->decoderObject) == DC_Reserved)
{
DC_Abort(pParams->decoderObject);
pImg->decoderObject = NULL;
pImg->flags &= ~IMG_LOADING;
}
}
pParams->pStatus = pSafeFree(pParams->pStatus);
if (pParams->pStatus == NULL && pParams->request)
{
Nuke_Request(pParams->request);
XX_DMsg(DBG_IMAGE, ("dangling pointer in ImageLoad\n"));
}
else Async_UnblockThread(pParams->parentThread);
return STATE_DONE;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
}
void DoUpdateImg(struct Params_Image_Fetch *pParams,BOOL bIsComplete)
{
struct _www *w3doc = pParams->twDoc->w3doc;
struct _element *aElements = w3doc->aElements;
int i;
long oldYbound = 0;
struct ImageInfo *myImage;
struct ImageInfo *target = aElements[pParams->nEl].myImage;
/* perhaps an img hint lied - shame,shame */
(void) W3Doc_CheckForImageLoad(w3doc);
/* reformat will redraw everything past the last formatted line */
if (w3doc->frame.nLastFormattedLine > 0)
oldYbound = w3doc->ybound;
TW_Reformat(pParams->twDoc, NULL);
aElements = w3doc->aElements;
for (i = pParams->nEl; i >= 0; i = aElements[i].next)
{
if (aElements[i].lFlags & ELEFLAG_BACKGROUND_IMAGE && aElements[i].myImage == target) {
if (bIsComplete)
TW_UpdateRect(pParams->twDoc, NULL); // invalidate entire window
break;
}
if (aElements[i].type == ELE_IMAGE || aElements[i].type == ELE_FORMIMAGE)
{
myImage = aElements[i].myImage;
if (myImage == target)
{
RECT rUpdate;
FrameToDoc( w3doc, i, &rUpdate );
#ifdef FEATURE_CLIENT_IMAGEMAP
if (aElements[i].lFlags & (ELEFLAG_USEMAP | ELEFLAG_IMAGEMAP | ELEFLAG_ANCHOR))
#else
if (aElements[i].lFlags & (ELEFLAG_IMAGEMAP | ELEFLAG_ANCHOR))
#endif
{
InsetRect(&rUpdate, aElements[i].border, aElements[i].border);
}
if (myImage->width)
{
OffsetRect(&rUpdate, -pParams->twDoc->offl, -pParams->twDoc->offt);
if (rUpdate.top < w3doc->ybound)
{
if (bIsComplete)
{
if (pParams->pImgUpdate)
(*(PDCIMGUPDATEPROC)(pParams->pImgUpdate))(myImage,pParams->twDoc,&rUpdate,pParams->logicalRowN+1,myImage->height-1);
else
TW_UpdateRect(pParams->twDoc, &rUpdate);
}
else
DC_UpdateRect(myImage->decoderObject,pParams->twDoc,&rUpdate,pParams->logicalRow0,pParams->logicalRowN);
}
}
}
}
}
}
#define STATE_FETCH_TRIEDLOAD (STATE_OTHER)
#define STATE_FETCH_SYNCLOAD (STATE_OTHER+1)
#define STATE_FETCH_MAPLOAD (STATE_OTHER+2)
static int Image_Fetch_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_Fetch *pParams;
int requestID;
DECODERSTATUS dcStatus;
enum GuitErrs errorCode;
struct _www *w3doc;
struct ImageInfo *pImg = NULL;
BOOL bCausedCompletion;
BOOL bSeized = FALSE;
BOOL bWasUnknown;
pParams = *ppInfo;
#define IMG_LOADMASK (IMG_ERROR|IMG_MISSING|IMG_NOTLOADED)
pParams->request = HTRequest_validate(pParams->request);
w3doc = tw == NULL ? NULL : pParams->twDoc->w3doc;
if (w3doc == NULL) goto exitAbort;
pImg = pImgLookup(pParams->twDoc,pParams->nEl);
if (pImg == NULL) goto exitAbort;
switch (nState)
{
case STATE_INIT:
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: Called for %s [element=%d] (request=%d)\n", pImg->srcURL,pParams->nEl,cbDC_GetRequestID(pImg->decoderObject)));
pParams->childThread = NULL;
if (pImg->flags & IMG_SEIZE)
{
pImg->flags &= ~IMG_SEIZE;
bSeized = TRUE;
}
pParams->request->destination = Dest_CreateDest(pImg->srcURL);
if (!pParams->request->destination)
{
goto exitAbort;
}
WAIT_SetStatusBarIcon( tw, SBI_ReceivingFromIcon );
pParams->request->referer = pParams->twDoc->w3doc->szActualURL;
pParams->logicalRow0 = -1;
pParams->logicalRowN = -1;
pParams->pImgUpdate = NULL;
{
struct Params_Image_Load *pLoadParams;
if (bSeized)
{
pParams->pStatus = GTR_CALLOC(1,sizeof(SAFERESULT));
if (pParams->pStatus == NULL)
{
return STATE_ABORT;
}
pParams->pStatus->status = TRUE;
pParams->pStatus->bSeized = TRUE;
}
else if (pParams->decoderObject &&
(pImg->flags & IMG_LOADING) &&
pParams->cbRequestID == cbDC_GetRequestID(pParams->decoderObject))
{
pLoadParams = GTR_MALLOC(sizeof(*pLoadParams));
if (pLoadParams == NULL) return STATE_ABORT;
pParams->pStatus = GTR_CALLOC(1,sizeof(SAFERESULT));
if (pParams->pStatus == NULL)
{
GTR_FREE(pLoadParams);
return STATE_ABORT;
}
pParams->request->cbRequestID = pParams->cbRequestID;
pLoadParams->request = pParams->request;
pLoadParams->pStatus = pParams->pStatus;
pLoadParams->decoderObject = pParams->decoderObject;
pLoadParams->cbRequestID = pParams->cbRequestID;
pLoadParams->nEl = pParams->nEl;
pLoadParams->twDoc = pParams->twDoc;
pParams->pStatus->refcnt++;
tw->image_request = NULL;
pLoadParams->parentThread = Async_GetCurrentThread();
/* It is important that HTLoadDocument_Async and it's descendents
pass around twDoc, which is a "REAL" Mwin. this is for error
reporting and wait cursor manipulation */
pParams->childThread = Async_StartThread(Image_Load_Async, pLoadParams, pParams->twDoc);
}
}
return STATE_FETCH_TRIEDLOAD;
case STATE_FETCH_TRIEDLOAD:
// NOTE: the first thread to call cbDC_BlockOnCompletion will
// set pImg->decoderObject to NULL.
requestID = -1;
errorCode = errNoError;
dcStatus = DC_Complete;
if (pImg->decoderObject)
{
requestID = cbDC_GetRequestID(pImg->decoderObject);
dcStatus = cbDC_BlockOnCompletion(pImg->decoderObject,&errorCode);
bCausedCompletion = requestID != cbDC_GetRequestID(pImg->decoderObject);
}
switch (dcStatus)
{
case DC_Complete:
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: Complete for %s (request=%d)\n", pImg->srcURL,requestID));
break;
case DC_WHKnown:
{
PIMGCBINFO pImgCBInfo = pDC_GetOutput(pImg->decoderObject);
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: w&h known for %s (request=%d) [w=%d h=%d]\n", pImg->srcURL,requestID,pImgCBInfo->width,pImgCBInfo->height));
bWasUnknown = !(pImg->flags & IMG_WHKNOWN);
pImg->width = pImgCBInfo->width;
pImg->height = pImgCBInfo->height;
pImg->flags |= IMG_WHKNOWN;
if (bWasUnknown) (void) W3Doc_CheckForImageLoad(w3doc);
TW_Reformat(pParams->twDoc, NULL);
}
Async_UnblockConditionally(MasterFilter,pParams->tw->twParent);
return STATE_FETCH_TRIEDLOAD;
case DC_ProgDraw:
{
PIMGCBINFO pImgCBInfo = pDC_GetOutput(pImg->decoderObject);
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: prog draw [%d] for %s (request=%d)\n", pImgCBInfo->logicalRow, pImg->srcURL,requestID));
pImg->width = pImgCBInfo->width;
pImg->height = pImgCBInfo->height;
pImg->flags |= IMG_WHKNOWN;
pParams->pImgUpdate = pDC_GetImgUpdate(pImg->decoderObject);
pParams->logicalRow0 = pParams->logicalRowN+1;
pParams->logicalRowN = pImgCBInfo->logicalRow;
DoUpdateImg(pParams,FALSE);
pImgCBInfo->bProgSeen = TRUE;
Async_UnblockConditionally(MasterFilter,pParams->tw->twParent);
}
return STATE_FETCH_TRIEDLOAD;
default:
return STATE_FETCH_TRIEDLOAD;
}
if (bCausedCompletion)
{
pImg->decoderObject = NULL;
if (errorCode == errNoError &&
((!pParams->pStatus) ||
pParams->pStatus->refcnt != 0 ||
pParams->pStatus->status) &&
!(pParams->request->iFlags & HTREQ_HAD_ERROR) &&
pImg->width &&
pImg->height)
{
XX_DMsg(DBG_IMAGE, ("Fetching %s succeeded\n", pImg->srcURL));
if (wg.eColorMode == 8)
{
#ifdef FEATURE_JPEG
if (pImg->flags & IMG_JPEG)
{
pImg->pbmi = BIT_Make_DIB_PAL_Header_Prematched(pImg->width, pImg->height,
pImg->data);
pImg->flags |= IMG_PREMATCHED;
}
else
#endif
{
/* if the data is already dithered due to progressive draw
pImg->flags & IMG_PREMATCHED is true and we pass
NULL for data to prevent redithering
*/
pImg->pbmi = BIT_Make_DIB_PAL_Header(pImg->width, pImg->height,
pImg->flags & IMG_PREMATCHED ? NULL:pImg->data,
pImg->hPalette, pImg->transparent);
pImg->flags |= IMG_PREMATCHED;
/*
We no longer need the image's palette
*/
if (pImg->hPalette)
{
DeleteObject(pImg->hPalette);
pImg->hPalette = NULL;
}
}
}
else
{
if (wg.eColorMode == 4)
{
#ifdef FEATURE_JPEG
if (pImg->flags & IMG_JPEG)
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_VGA(pImg->width, pImg->height,
pImg->data);
}
else
#endif
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_Screen(pImg->width, pImg->height,
pImg->data, pImg->hPalette, pImg->transparent, pImg->flags);
}
}
else
{
#ifdef FEATURE_JPEG
/* true color display */
if (pImg->flags & IMG_JPEG)
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_24BIT(pImg->width, pImg->height,
pImg->data);
}
else
#endif
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_Screen(pImg->width, pImg->height,
pImg->data, pImg->hPalette, pImg->transparent, pImg->flags);
}
}
}
/* If Image is equal to old version, swap back */
if (pImg->pImgOtherVers &&
pImg->cbCheckSum == pImg->pImgOtherVers->cbCheckSum)
{
Image_Revert(pImg);
Image_Swap(w3doc,pImg,pImg->pImgOtherVers);
}
}
else
{
/* If we don't already have error flags, make something up. If the global
abort flag is set, assume that that's why the load failed. Otherwise,
it must have been a bona fide error. */
if (!pImg->flags || (pImg->flags & IMG_NOTLOADED) ||
(pParams->request->iFlags & HTREQ_HAD_ERROR) )
pImg->flags = IMG_ERROR | (pImg->flags & ~IMG_LOADMASK);
if (pParams->pImgThreads->errElement < 0 ||
pParams->pImgThreads->errElement > pParams->nEl)
pParams->pImgThreads->errElement = pParams->nEl;
/* If backup Image, swap back */
if (pImg->pImgOtherVers)
{
Image_Revert(pImg);
Image_Swap(w3doc,pImg,pImg->pImgOtherVers);
pParams->logicalRowN = -1;
}
}
}
else
{
if (!(pImg->flags & IMG_ERROR))
{
/* If Image is equal to old version, swap back */
if (pImg->pImgOtherVers &&
pImg->cbCheckSum == pImg->pImgOtherVers->cbCheckSum)
{
Image_Revert(pImg);
Image_Swap(w3doc,pImg,pImg->pImgOtherVers);
}
}
else
{
if (pParams->pImgThreads->errElement < 0 ||
pParams->pImgThreads->errElement > pParams->nEl)
pParams->pImgThreads->errElement = pParams->nEl;
/* If backup Image, swap back */
if (pImg->pImgOtherVers)
{
Image_Revert(pImg);
Image_Swap(w3doc,pImg,pImg->pImgOtherVers);
pParams->logicalRowN = -1;
}
}
}
// Image_Swap may have hosed pImg!
pImg = pImgLookup(pParams->twDoc,pParams->nEl);
DoUpdateImg(pParams,TRUE);
if (pParams->pStatus && pParams->pStatus->refcnt != 0)
{
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: block on load of %s\n",pImg ? pImg->srcURL:"Dead Image"));
Async_BlockThread(Async_GetCurrentThread());
}
return STATE_FETCH_SYNCLOAD;
case STATE_FETCH_SYNCLOAD:
if (pParams->decoderObject)
{
if (pParams->pStatus->status)
{
#ifdef FEATURE_CLIENT_IMAGEMAP
struct _element *aElements = w3doc->aElements;
#endif
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: download %s succeeded\n", pImg->srcURL));
#ifdef FEATURE_CLIENT_IMAGEMAP
if (aElements[pParams->nEl].lFlags & ELEFLAG_USEMAP &&
aElements[pParams->nEl].myMap->flags == MAP_NOTLOADED)
{
struct Params_Map_Fetch *pmf;
pmf = GTR_MALLOC(sizeof(*pmf));
if (pmf == NULL) return STATE_ABORT;
pmf->pMap = aElements[pParams->nEl].myMap;
pmf->fNotFromCache = pParams->request->fNotFromCache;
Async_DoCall(Map_Fetch_Async, pmf);
return STATE_FETCH_MAPLOAD;
}
#endif
}
else
{
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: download %s failed\n", pImg->srcURL));
}
}
/* FALL THROUGH */
case STATE_FETCH_MAPLOAD:
goto exitDone;
case STATE_ABORT:
// if someone aborts we can't be sure whether its really an error.
if ( pImg )
pImg->flags = (~IMG_ERROR & pImg->flags);
goto exitAbort;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
exitAbort:
if (bExistsAnother(pParams->pStatus) && pParams->childThread)
{
Async_TerminateThread(pParams->childThread);
}
if (pParams->decoderObject && pParams->cbRequestID == cbDC_GetRequestID(pParams->decoderObject))
{
DC_Abort(pParams->decoderObject);
if (pImg)
{
pImg->decoderObject = NULL;
pImg->flags &= ~IMG_LOADING;
if (pImg->pImgOtherVers)
{
Image_Revert(pImg);
if (w3doc) Image_Swap(w3doc,pImg,pImg->pImgOtherVers);
}
}
}
exitDone:
if (pParams->bWasVisible) pParams->pImgThreads->status--;
pParams->pImgThreads = pSafeFree(pParams->pImgThreads);
#ifdef XX_DEBUG
if (pParams->pImgThreads == NULL) XX_DMsg(DBG_IMAGE, ("dangling pointer in ImageFetch\n"));
#endif
if (pParams->pImgThreads != NULL)
{
Async_UnblockConditionally(MasterFilter,pParams->tw->twParent);
}
bSeized = (pParams->pStatus != NULL) && pParams->pStatus->bSeized;
pParams->pStatus = pSafeFree(pParams->pStatus);
if (tw && pParams->request && pParams->pStatus == NULL && !bSeized)
{
Nuke_Request(pParams->request);
if (tw->image_request == pParams->request) tw->image_request = NULL;
}
if (tw) Plan_close(pParams->tw);
return STATE_DONE;
}
void Image_DeleteAll(void)
{
int i;
int count;
struct ImageInfo *img;
count = Hash_Count(&gImageCache);
XX_DMsg(DBG_IMAGE, ("Image_DeleteAll: count=%d\n", count));
for (i = 0; i < count; i++)
{
Hash_GetIndexedEntry(&gImageCache, i, NULL, NULL, (void **) &img);
#ifdef XX_DEBUG
if (img->refCount)
XX_DMsg(DBG_IMAGE, ("RefCount = %d in Image_DeleteAll, URL = %s\n", img->refCount,img->srcURL));
#endif
x_DisposeImage(img, TRUE);
}
Hash_FreeContents(&gImageCache);
}
// FilterProc for the unblock conditionally on loadall blocked for parser
static boolean ParseFilter(ThreadID theThread,void *context)
{
struct Mwin *tw = Async_GetWindowFromThread(theThread);
if (tw && TW_GETBLOCKED(tw,TW_PARSEBLOCKED) &&
(tw->twParent == context || (tw->twParent == NULL && tw == context)))
{
TW_CLEARBLOCKED(tw,TW_PARSEBLOCKED);
return TRUE;
}
return FALSE;
}
void Image_UnblockMaster(struct Mwin *twDoc)
{
Async_UnblockConditionally(ParseFilter,twDoc);
}
static BOOL bImgDuplicate(struct _element *aElements,int nElLast,struct ImageInfo *myImage)
{
int i;
for (i = 0 ; i != nElLast;i = aElements[i].next)
{
if (aElements[i].type == ELE_IMAGE || aElements[i].type == ELE_FORMIMAGE)
if (aElements[i].myImage == myImage) return TRUE;
}
return FALSE;
}
#ifdef TEST_DCACHE_OPTIONS
#ifdef DEBUG
extern BOOL bFavorVisibleImages;
#endif
#endif
/* Load all images in the document which are marked as IMG_NOTLOADED */
#define STATE_LOADALL_GETNEXT (STATE_OTHER)
#define STATE_LOADALL_GOTONE (STATE_OTHER+1)
#define STATE_LOADALL_WAITING (STATE_OTHER+2)
#define STATE_LOADALL_REAPING (STATE_OTHER+3)
int Image_LoadAll_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_LoadAll *pParams = *ppInfo;
struct _element *aElements;
struct _www *w3doc = NULL;
struct Mwin *twParent = NULL;
int nLastGood;
BOOL bWasVisible;
BOOL bFileURL;
struct ImageInfo *myImage;
if (tw)
{
twParent = pParams->tw->twParent ? pParams->tw->twParent : pParams->tw;
w3doc = twParent->w3doc;
}
if (w3doc == NULL)
{
if (nState != STATE_INIT) nState = STATE_ABORT;
}
else aElements = w3doc->aElements;
switch (nState)
{
case STATE_INIT:
if (!pParams->bJustOne) pParams->nEl = 0;
if (pParams->bJustOne || (pParams->tw->twParent == NULL))
{
WAIT_Push(tw, waitPartialInteract, "");
}
tw->dwSslPageFlagsWorking &= ~SSL_PAGE_MIXED_WARNING_GIVEN;
pParams->nLastDone = -1;
pParams->decoderObject = NULL;
pParams->cbImgLoadCount = gcbImgLoadCount;
pParams->pImgThreads = GTR_CALLOC(1,sizeof(SAFEIMGRESULT));
pParams->pImgThreads->errElement = -1;
pParams->bInRecovery = FALSE;
pParams->bDontGoToNextEle = FALSE;
if (pParams->pImgThreads == NULL) goto exitDone;
if (w3doc == NULL) goto exitDone;
// NOTE: we ALWAYS load image for HTML cons'ed to show link to image
if (w3doc->bIsImage) pParams->bLocalOnly = FALSE;
WAIT_SetStatusBarIcon( tw, SBI_ReceivingFromIcon );
return STATE_LOADALL_GETNEXT;
case STATE_LOADALL_GETNEXT:
/* Find the next unloaded picture */
nLastGood = pParams->nEl;
if (w3doc->elementCount == 0) pParams->nEl = -1;
else if (nLastGood == pParams->nLastDone)
pParams->nEl = aElements[nLastGood].next;
for ( ; pParams->nEl >= 0; pParams->nEl = aElements[pParams->nEl].next)
{
// Is this a blob?????
// Don't attempt to load blob here if hidden element (used for background
// download of VRML inline files)
//
if (aElements[pParams->nEl].pblob &&
((!(aElements[pParams->nEl].lFlags & ELEFLAG_HIDDEN)) ||
pParams->bJustOne))
{
struct Params_LoadBackgroundBlobs *pPLBB;
PDECODER pDecoder;
// if its the first time we hit this code for a particalar element
// and this is NOT a "Load Just One item", and there is a LowSrc
// image, then we must hack it so the LowSrc image
// is downloaded first
if ( pParams->bDontGoToNextEle == FALSE && !pParams->bJustOne &&
aElements[pParams->nEl].myImage && aElements[pParams->nEl].myImage->srcURL)
{
// keep us from going to next element until we have the
// image and the Blob downloaded.
pParams->bDontGoToNextEle = TRUE;
goto LDo_Image_First;
}
LDo_CancelImageFirst: // for some reason we decided not to download this image first
// make sure we Go to the next element
pParams->bDontGoToNextEle = FALSE;
pDecoder = pDC_Reserve(pParams->tw,pParams->bInRecovery);
if (NULL == pDecoder)
{
// hack to prevent infinite loop in recovery mode
// if there is good AVI but bad image on the same element
if ( pParams->bInRecovery &&
( (aElements[pParams->nEl].type == ELE_IMAGE && !gPrefs.bAutoLoadVideos )
|| (aElements[pParams->nEl].pblob->dwFlags & (BLOB_FLAGS_LOADED|BLOB_FLAGS_LOADING|BLOB_FLAGS_ERROR) ) ) &&
aElements[pParams->nEl].myImage && aElements[pParams->nEl].myImage->srcURL )
goto LDo_Image_First;
else if ( !pParams->bInRecovery &&
(aElements[pParams->nEl].type == ELE_IMAGE && !gPrefs.bAutoLoadVideos ))
return STATE_LOADALL_GOTONE;
return STATE_LOADALL_GETNEXT;
}
pPLBB = GTR_MALLOC(sizeof(*pPLBB));
if (NULL == pPLBB){
makeAvailable(pDecoder);
return STATE_ABORT;
}
pPLBB->twDoc = twParent;
pPLBB->iIndex = pParams->nEl;
pPLBB->pImgThreads = pParams->pImgThreads;
pPLBB->thidParent = Async_GetCurrentThread();
pPLBB->bLocalOnly = pParams->bLocalOnly;
pPLBB->bNoImageCache = pParams->bNoImageCache;
pPLBB->pDecoder = pDecoder;
// need to propage this flag to the blob code,
// since we figure out whether to generate errors or not
pPLBB->bJustOne = pParams->bJustOne;
pParams->pImgThreads->refcnt++;
Async_StartThread(LoadBackgroundBlobs_Async, pPLBB,twParent);
// move on to the next element.
return STATE_LOADALL_GOTONE;
}
LDo_Image_First:
nLastGood = pParams->nEl;
if (aElements[pParams->nEl].type == ELE_IMAGE || aElements[pParams->nEl].type == ELE_FORMIMAGE)
{
if (aElements[pParams->nEl].myImage->srcURL)
{
myImage = aElements[pParams->nEl].myImage;
bFileURL = !strncmp(myImage->srcURL, "file:", 5);
if (((pParams->bInRecovery && !bFileURL) || pParams->bJustOne) &&
(myImage->flags & IMG_ERROR))
myImage->flags = IMG_NOTLOADED;
if ((myImage->flags & IMG_NOTLOADED) ||
(pParams->bNoImageCache && myImage->cbImgLoadCount < pParams->cbImgLoadCount))
{
/* This is an unloaded picture. Do we want to load it? */
if ((!pParams->bLocalOnly) ||
bFileURL ||
(myImage->flags & IMG_LOADING))
{
/* NOTE: we only spawn one lightweight thread per image/doc pair */
if (!(myImage->flags & IMG_LOADING) || !bImgDuplicate(aElements,pParams->nEl,myImage))
{
/* Yes, proceed */
myImage->flags &= ~IMG_LOADSUP;
break;
}
}
if (pParams->bLocalOnly)
{
myImage->flags |= IMG_LOADSUP;
TW_Reformat(twParent, NULL);
aElements = w3doc->aElements;
}
}
}
}
// if we failed to proceed with downloading the
// image, then don't skip this current BLOB !
if ( pParams->bDontGoToNextEle )
goto LDo_CancelImageFirst;
} // end of for loop
if (pParams->nEl < 0)
{
XX_Assert((!pParams->bDontGoToNextEle),
("Come Get ArthurBI RIGHT NOW. I'm asserting that this case won't happen, when nEl < 0 and bDontGoToNextEle is TRUE"));
if ((!pParams->bJustOne) && twParent->bLoading)
{
pParams->nEl = nLastGood;
Async_BlockThread(Async_GetCurrentThread());
TW_SETBLOCKED(pParams->tw,TW_PARSEBLOCKED);
return STATE_LOADALL_GETNEXT;
}
XX_DMsg(DBG_IMAGE, ("last element inspected %d of %d\n", nLastGood,w3doc->elementCount));
if (pParams->pImgThreads->refcnt)
{
Async_BlockThread(Async_GetCurrentThread());
TW_SETBLOCKED(pParams->tw,TW_REAPBLOCKED);
return STATE_LOADALL_REAPING;
}
/* There are no more unloaded pictures */
w3doc->bHasMissingImages = W3Doc_HasMissingImages(w3doc);
goto exitDone;
}
/* OK, let's bring in this picture */
{
struct Params_Image_Fetch *pif;
if (aElements[pParams->nEl].myImage->flags & IMG_SEIZE)
{
bWasVisible = TRUE;
}
else
{
bWasVisible = bImgCheckForVisible(w3doc,pParams->nEl);
#ifdef TEST_DCACHE_OPTIONS
#ifdef DEBUG
if (bFavorVisibleImages)
{
#endif
#endif
if ((!bWasVisible) && pParams->pImgThreads->status)
{
XX_DMsg(DBG_IMAGE, ("blocking invisible element %d,visible threads = %d\n", pParams->nEl,pParams->pImgThreads->status));
Async_BlockThread(Async_GetCurrentThread());
TW_SETBLOCKED(pParams->tw,TW_VISBLOCKED);
// we're blocking on an invisible element
// therefore we should NOT get our BLOB
// since we need to re-enter to this state
// and continue getting this image.
pParams->bDontGoToNextEle = FALSE;
return STATE_LOADALL_GETNEXT;
}
#ifdef TEST_DCACHE_OPTIONS
#ifdef DEBUG
}
#endif
#endif
}
// reserve a decoder thread - if all are in use, NULL will be
// returned and we will be blocked as side effect
if (aElements[pParams->nEl].myImage->decoderObject == NULL)
{
pParams->decoderObject = pDC_Reserve(pParams->tw,pParams->bInRecovery);
if (pParams->decoderObject == NULL)
{
// make sure to not get a blob on reentry to this
// state. Since we're not finished on this image
// We're waiting for a decoder thread
pParams->bDontGoToNextEle = FALSE;
return STATE_LOADALL_GETNEXT;
}
}
pif = GTR_CALLOC(1,sizeof(*pif));
if (pif == NULL) return STATE_ABORT;
if (!(aElements[pParams->nEl].myImage->flags & IMG_NOTLOADED))
Image_Nuke(w3doc,pParams->nEl,TRUE, TRUE);
myImage = aElements[pParams->nEl].myImage;
pif->tw = NewMwin(GIMGSLAVE);
if (pif->tw == NULL) return STATE_ABORT;
if (!(myImage->flags & IMG_LOADING))
{
myImage->flags |= IMG_LOADING;
myImage->cbImgLoadCount = gcbImgLoadCount++;
}
if (pParams->decoderObject)
myImage->decoderObject = pParams->decoderObject;
if (myImage->flags & IMG_SEIZE)
{
myImage->cbImgLoadCount = gcbImgLoadCount++;
pParams->decoderObject = myImage->decoderObject;
}
pif->tw->twParent = pParams->tw;
pif->decoderObject = pParams->decoderObject;
pif->pImgThreads = pParams->pImgThreads;
pif->bWasVisible = bWasVisible;
pParams->decoderObject = NULL;
if (bWasVisible) pParams->pImgThreads->status++;
pParams->pImgThreads->refcnt++;
pif->request = pif->tw->image_request;
// if we're not loading them individually then
// don't force an error message on each one.
if ( !pParams->bJustOne )
pif->request->iFlags |= HTREQ_STOP_WHINING;
pif->request->fNotFromCache = pParams->bNoImageCache;
pif->twDoc = twParent;
pif->nEl = pParams->nEl;
if (pif->decoderObject) pif->cbRequestID = cbDC_GetRequestID(pif->decoderObject);
pif->request->destination = NULL;
Async_StartThread(Image_Fetch_Async, pif,pif->tw);
}
return STATE_LOADALL_GOTONE;
case STATE_LOADALL_GOTONE:
// if we had an error and we aren't already in recovery
// we wait for all threads to finish to minimize load
// on server
if (pParams->pImgThreads->errElement >= 0 &&
(!pParams->bInRecovery) &&
(!pParams->bLocalOnly) &&
(!pParams->bJustOne))
return STATE_LOADALL_REAPING;
// if we've downloaded an image for a blob, then we need
// to go back and download the Blob itself, NOW
if ( pParams->bDontGoToNextEle == TRUE )
return STATE_LOADALL_GETNEXT;
nLastGood = pParams->nEl;
pParams->nLastDone = pParams->nEl;
if (pParams->bJustOne)
{
pParams->nEl = -1;
}
else
{
pParams->nEl = aElements[pParams->nEl].next;
if (pParams->nEl < 0) pParams->nEl = nLastGood;
}
return STATE_LOADALL_GETNEXT;
case STATE_LOADALL_REAPING:
/* There are no more unloaded pictures */
if (pParams->pImgThreads->refcnt)
{
Async_BlockThread(Async_GetCurrentThread());
TW_SETBLOCKED(pParams->tw,TW_REAPBLOCKED);
return STATE_LOADALL_REAPING;
}
// if we had an error and we aren't already in recovery
// we wait for all threads to finish to minimize load
// on server
if (pParams->pImgThreads->errElement >= 0 &&
(!pParams->bInRecovery) &&
(!pParams->bLocalOnly) &&
(!pParams->bJustOne))
{
if (twParent->bLoading)
{
Async_BlockThread(Async_GetCurrentThread());
TW_SETBLOCKED(pParams->tw,TW_PARSEBLOCKED);
return STATE_LOADALL_REAPING;
}
XX_DMsg(DBG_IMAGE, ("entering recovery mode starting at element %d\n", pParams->pImgThreads->errElement));
pParams->nLastDone = -1;
pParams->nEl = pParams->pImgThreads->errElement;
pParams->bInRecovery = TRUE;
// if we're going back make sure we don't loop infinitely
// trying to get this AVI, since we're reseting the element counter
pParams->bDontGoToNextEle = FALSE;
return STATE_LOADALL_GETNEXT;
}
w3doc->bHasMissingImages = W3Doc_HasMissingImages(w3doc);
goto exitDone;
case STATE_ABORT:
if(pParams->decoderObject) DC_Abort(pParams->decoderObject);
if (w3doc)
{
Async_TerminateByWindow(tw);
(void) W3Doc_CheckForImageLoad(w3doc);
w3doc->bIsShowPlaceholders = TRUE; // show unloaded images as placeholders
TW_Reformat(twParent, NULL);
w3doc->bHasMissingImages = W3Doc_HasMissingImages(w3doc);
}
goto exitDone;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
exitDone:
if (tw)
{
if (pParams->bJustOne || (pParams->tw->twParent == NULL))
{
WAIT_Pop(tw);
}
if (twParent = pParams->tw->twParent)
{
TW_CLEARFLAG(twParent,TW_LOADALLACTIVE);
if (TW_GETBLOCKED(twParent,TW_LOADALLBLOCKED))
{
TW_CLEARBLOCKED(twParent,TW_LOADALLBLOCKED);
Async_UnblockThread(pParams->parentThread);
}
Plan_close(pParams->tw);
}
else
{
TW_CLEARBLOCKED(pParams->tw,TW_REAPBLOCKED);
TW_CLEARBLOCKED(pParams->tw,TW_VISBLOCKED);
TW_CLEARBLOCKED(pParams->tw,TW_PARSEBLOCKED);
}
}
if (pParams->pImgThreads) pParams->pImgThreads = pSafeFree(pParams->pImgThreads);
#ifdef XX_DEBUG
if (pParams->pImgThreads) XX_DMsg(DBG_IMAGE, ("dangling pointer in LoadAllImages\n"));
#endif
return STATE_DONE;
}
// Counts the number of occurences of pImg in w3doc.
int Image_CountRefs(struct _www *w3doc,struct ImageInfo *pImg)
{
int cbCount = 0;
struct _element *aElements = w3doc->aElements;
int i;
if (pImg->refCount == 1) return 1;
for (i = 0; i >= 0; i = aElements[i].next)
{
if ((aElements[i].type == ELE_IMAGE || aElements[i].type == ELE_FORMIMAGE) && aElements[i].myImage == pImg)
cbCount++;
}
return cbCount;
}
// Swaps one version of an image for another.
static void Image_Swap(struct _www *w3doc,struct ImageInfo *pOld,struct ImageInfo *pNew)
{
struct _element *aElements = w3doc->aElements;
int i;
for (i = 0; i >= 0; i = aElements[i].next)
{
if ((aElements[i].type == ELE_IMAGE || aElements[i].type == ELE_FORMIMAGE) && aElements[i].myImage == pOld)
{
Image_AddRef(pNew);
Image_NukeRef(pOld);
aElements[i].myImage = pNew;
}
}
}
// if pOld is the image in the hash table (current version bound to URL), takes
// pOld out of hash table (and performs equivalent with persistent dcache) and puts
// pOld->pImgOtherVers instead.
// ASSUMES that pOld->pImgOtherVers != NULL
static void Image_Revert(struct ImageInfo *pOld)
{
int ndx;
struct ImageInfo *pHashImg;
struct ImageInfo *pNew = pOld->pImgOtherVers;
XX_Assert((pNew != NULL), ("Image Revert called w/o old vers: %s", pOld->srcURL));
ndx = Hash_Find(&gImageCache, pOld->srcURL, NULL, (void **) &pHashImg);
if (pHashImg == pOld)
{
// DEEPAK: here you put pOld in aux cache and remove it from real cache
MoveDCacheEntryToAux(pOld->actualURL, pOld);
Hash_DeleteIndexedEntry(&gImageCache, ndx);
// DEEPAK: here you remove pNew from aux cache and put it back into real cache
MoveAuxEntryToDCache(pNew);
Hash_Add(&gImageCache, pNew->srcURL, NULL, (void *) pNew);
}
}
// If exists, returns persistent cache path corresponding to the image. The
// caller is responsible for freeing the string.
char * pImage_GetDCachePath(PCImageInfo pImg)
{
char *pPath = NULL;
char *pResolvedURL = NULL;
int ndx;
struct ImageInfo *pHashImg;
if (!gPrefs.bEnableDiskCache)
return NULL;
ndx = Hash_Find(&gImageCache, pImg->srcURL, NULL, (void **) &pHashImg);
if (pHashImg == pImg)
{
// Image is the current value for URL
pResolvedURL = GetResolvedURL(pImg->actualURL,NULL,NULL,&pPath,NULL,TRUE);
}
else
{
// Image (pImg) is in the auxilliary cache (we hope)
// DEEPAK: here you'd do the aux cache version of GetResolvedURL
pResolvedURL = GetResolvedURLAux(pImg, &pPath);
}
if (pResolvedURL) GTR_FREE(pResolvedURL);
return pPath;
}
// Frees image info for image at element cbElement in w3doc. In the case of
// FEATURE_IMG_THREADS, creates a new version of the image instead, if there
// exist references to the image from some other w3doc.
static BOOL Image_Nuke(struct _www *w3doc,int cbElement,BOOL bNukeMaps, BOOL bNukeDCache)
{
BOOL bSomethingNuked = FALSE;
struct _element *anElement = &w3doc->aElements[cbElement];
struct ImageInfo *myImage = anElement->myImage;
int cbRefs;
int ndx;
struct ImageInfo *pNewImg;
struct ImageInfo *pHashImg;
if (bNukeDCache && gPrefs.bEnableDiskCache && anElement->pblob &&
anElement->pblob->szURL )
{
// Note: We're counting on the blob to be removed from
anElement->pblob->dwFlags &= ~( BLOB_FLAGS_LOADING | BLOB_FLAGS_FIXUP | BLOB_FLAGS_LOADED );
FlushDCacheEntry(anElement->pblob->szURL);
}
if ((!(myImage->flags & (IMG_NOTLOADED | IMG_ERROR | IMG_MISSING))) &&
(cbRefs = Image_CountRefs(w3doc,myImage)) != myImage->refCount)
{
ndx = Hash_Find(&gImageCache, myImage->srcURL, NULL, (void **) &pHashImg);
if (pHashImg == myImage)
{
// DEEPAK: here you would delete myImage from real cache and move
// it into aux cache
MoveDCacheEntryToAux(myImage->actualURL, myImage);
Hash_DeleteIndexedEntry(&gImageCache, ndx);
}
// DEEPAK: i don't know if you do anything, but pNewImg will become
// the real cache entry for this URL once HTLoad is started.
/* I don't do anything on this because this is just a place holder. The
* dcache entry for this gets created in the HTLoad routines later on.
*/
pNewImg = Image_CreatePlaceholder(myImage->srcURL,0,0);
if (pNewImg == NULL)
{
Hash_Add(&gImageCache, myImage->srcURL, NULL, (void *) myImage);
return bSomethingNuked;
}
else
{
pNewImg->pImgOtherVers = myImage;
myImage->pImgOtherVers = pNewImg;
Image_Swap(w3doc,myImage,pNewImg);
}
bSomethingNuked = TRUE;
}
else if (!(myImage->flags & IMG_NOTLOADED))
{
/* If this is merely a placeholder, there may not be any image to delete */
x_DisposeImage(myImage, FALSE);
myImage->width = myImage->height = 0;
myImage->flags = IMG_NOTLOADED;
/* Note that myImage->srcURL is carefully left intact. */
bSomethingNuked = TRUE;
if (bNukeDCache && gPrefs.bEnableDiskCache)
FlushDCacheEntry(myImage->actualURL);
}
#ifdef FEATURE_CLIENT_IMAGEMAP
if (bNukeMaps && anElement->lFlags & ELEFLAG_USEMAP)
{
Map_Unload(anElement->myMap);
}
#endif
return bSomethingNuked;
}
/* Remove all images in a document and replace them with placeholders */
BOOL Image_NukeImages(struct _www *pdoc, BOOL bNukeMaps, BOOL bNukeDCache)
{
int n;
BOOL bSomethingNuked = FALSE;
for (n = 0; n < pdoc->elementCount; n++)
{
if ((pdoc->aElements[n].type == ELE_IMAGE || pdoc->aElements[n].type == ELE_FORMIMAGE))
if (Image_Nuke(pdoc,n,bNukeMaps,bNukeDCache))
bSomethingNuked = TRUE;
}
return bSomethingNuked;
}