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.
 
 
 
 
 
 

1112 lines
36 KiB

/*
Enhanced NCSA Mosaic from Spyglass
"Guitar"
Copyright 1994 Spyglass, Inc.
All Rights Reserved
Author(s):
Jim Seidman [email protected]
Hacked on by:
dpg progressive images.
scott piette X-11 support, builtin support.
*/
#include "all.h"
#ifdef MAC /* Include mac headers */
#include "WinDraw.h"
#endif
/* TODO why is the far keyword here? */
far struct hash_table gImageCache;
static void dispose_imageinfo(struct ImageInfo *img)
{
if (img->llElements)
{
HTList_delete(img->llElements);
}
x_DisposeImage(img);
GTR_FREE(img);
}
#ifdef USE_MEMMANAGE
/* Reduce the amount of memory used by images. The routine ignores nWanted,
since it's not easy to tell how much we're freeing anyway. */
static BOOL Image_ReduceMemory(int nWanted)
{
int ndx;
int count;
struct ImageInfo *img;
BOOL bDidFree;
bDidFree = FALSE;
ndx = 0;
count = Hash_Count(&gImageCache);
/* Find every image that isn't currently referenced by a document and
delete it. */
while (ndx < count)
{
Hash_GetIndexedEntry(&gImageCache, ndx, NULL, NULL, (void **) &img);
if (!img->refCount && !(img->flags & IMG_BUILTIN))
{
dispose_imageinfo(img);
Hash_DeleteIndexedEntry(&gImageCache, ndx);
bDidFree = TRUE;
count--;
}
else
{
ndx++;
}
}
return bDidFree;
}
#endif
static void Image_InitHash(void)
{
static BOOL bInitialized = FALSE;
if (!bInitialized)
{
Hash_Init(&gImageCache);
/* Is this MAC specific. Not very descriptive ifdef #@!?. <Scott> */
#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
bInitialized = TRUE;
}
}
static int Image_AddToCache(const char *url, struct ImageInfo *myImage)
{
struct ImageInfo *img;
int ndx;
int count;
int deleteMe;
count = Hash_Count(&gImageCache);
if (count >= gPrefs.image_cache_size)
{
deleteMe = -1;
for (ndx = 0; ndx < count; ndx++)
{
Hash_GetIndexedEntry(&gImageCache, ndx, NULL, NULL, (void **) &img);
if (!img->refCount && !(img->flags & IMG_BUILTIN))
{
deleteMe = ndx;
break;
}
}
if (deleteMe >= 0)
{
XX_DMsg(DBG_IMAGE, ("Deleting entry %d from the image cache\n", deleteMe));
/* If this is merely a placeholder, there may not be any image to delete */
dispose_imageinfo(img);
Hash_DeleteIndexedEntry(&gImageCache, deleteMe);
}
else
{
/* The cache is now overfull */
XX_DMsg(DBG_IMAGE, ("Need to delete an image from the cache, but cannot\n"));
}
}
return Hash_Add(&gImageCache, url, NULL, (void *) myImage);
}
/*
The HTGIF and HTXBM classes call this function when a complete image
has been received.
For Progressive images, this function is called once we have complete
header information.
*/
#if defined (WIN32)
struct ImageInfo * Image_SetImageData (HTRequest *request, unsigned char *data, int width,
int height, HPALETTE hPalette, long transparent, unsigned int flags)
#elif defined (MAC)
struct ImageInfo * Image_SetImageData(HTRequest *request, GWorldPtr gw, BitMap *mask, int width, int height)
#elif defined (UNIX)
struct ImageInfo * Image_SetImageData (HTRequest *request, unsigned char *data, unsigned char *mask, int width,
int height, XColor *xPalette, long transparent, int depth, int flags)
#endif
{
struct ImageInfo *pImg;
XX_DMsg(DBG_IMAGE, ("Image_SetImageData: Called for %s (w = %d, h =%d)\n",
request->destination->szRequestedURL, width, height));
/* Find the entry for this image in the cache */
pImg = NULL;
Hash_Find (&gImageCache, request->destination->szRequestedURL, NULL,
(void **) &pImg);
if (!pImg)
{
XX_DMsg(DBG_IMAGE,
("Image_SetImageData: No image placeholder exists for '%s'\n",
request->destination->szRequestedURL));
return (struct ImageInfo *) NULL;
}
#ifdef UNIX
if (!(flags & IMG_ISIMAGE))
x_DisposeImage(pImg);
#else
x_DisposeImage(pImg);
#endif
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;
pImg->compositeBackground = NULL;
pImg->mask = 0;
#endif
#ifdef UNIX
pImg->data = NULL;
pImg->xPalette = NULL;
pImg->depth = 0;
pImg->xpix = 0;
pImg->bg_height = 0;
pImg->bg_width = 0;
pImg->bg_xpix = 0;
pImg->ximg = 0;
pImg->clip_pix = 0;
pImg->transparent = -1;
#endif
}
else
{
pImg->width = width;
pImg->height = height;
pImg->nPreviousLastRow = 0;
pImg->nPreviousPass = 0;
pImg->nLastRow = 0;
pImg->nPass = 0;
pImg->bFirstPass = FALSE;
#ifdef WIN32
pImg->data = data;
pImg->hPalette = hPalette;
pImg->transparent = transparent;
pImg->flags = flags;
#endif
#ifdef MAC
pImg->gw = gw;
pImg->compositeBackground = NULL;
pImg->flags = 0;
pImg->mask = mask;
#endif
#ifdef UNIX
pImg->data = data;
pImg->mask = mask;
pImg->xPalette = xPalette;
pImg->depth = depth;
pImg->transparent = transparent;
pImg->flags = flags;
pImg->bg_height = 0;
pImg->bg_width = 0;
pImg->bg_xpix = 0;
#endif
}
return pImg;
}
struct ImageInfo *
Image_CreatePlaceholder(const char *full_address, int width, int height,
struct _www *w3doc, int element)
{
struct ImageInfo *myImage;
Image_InitHash();
/*
Check to see if it's in the cache
*/
myImage = NULL;
Hash_Find(&gImageCache, full_address, NULL, (void **) &myImage);
if (!myImage)
{
myImage = (struct ImageInfo *) GTR_CALLOC(sizeof(struct ImageInfo), 1);
if (myImage)
{
GTR_strncpy(myImage->src, full_address, MAX_URL_STRING);
myImage->flags = IMG_NOTLOADED;
myImage->width = 0;
myImage->height = 0;
Image_AddToCache(full_address, myImage);
}
}
if (element >= 0)
{
Image_AddElement (myImage, w3doc, element);
}
myImage->refCount++;
return myImage;
}
static int Fetch_Image_Wrapper_Async (struct Mwin *tw, int nState, void **ppInfo);
struct Params_Image_Wrapper {
struct Params_Image_Fetch *pif;
struct Mwin * tw; /* Window controlling load */
ThreadID parent_thread;
TKey key;
/* Variables used internally */
int *pStatus;
};
int Request_Fetch_Image_Async (struct Mwin *tw, int nState, void **ppInfo);
/*
** This function controls how many image loading processes
** are going on simultaneously. It actually runs synchronously
** in that it will block until it satisfies the request.
**
** So as long as we are under our limit on open connections,
** it will return immediately. after that it will block
** until such time as it can satisfy the request.
*/
/*
** Note that this current setup only works if all images for
** a given document are called via the same thread. i.e.
** if two different threads were to make calls to Request_Fetch_Image_Async()
** on the same TW it would probably deadlock.
*/
/* It shared the Image_Fetch structure. (actually needs a subclass
** of it, but C doesn't do that last I checked, so I hacked on the
** Image_Fetch structure
*/
#ifdef FEATURE_ASYNC_IMAGES
int Request_Fetch_Image_Async (struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_Fetch *pParams;
struct Params_Image_Fetch *pif;
struct Params_Image_Wrapper *piw;
pParams = *ppInfo;
switch (nState)
{
case STATE_INIT:
if (!pParams->key)
{
pParams->key = (int) pParams->tw;
/* pParams->key = Async_GetKey (); */
XX_DMsg(DBG_NOT, ("Setting key %lx\n", pParams->key));
}
/* FALLTHROUGH */
case STATE_OTHER:
if (tw->nOpenConnections >= gPrefs.nMaxConnections)
{
XX_DMsg(DBG_NOT, ("Locking thread w/ key %lx\n", pParams->key));
Async_LockThread (Async_GetCurrentThread(), pParams->key);
return STATE_OTHER;
}
pif = (struct Params_Image_Fetch *)GTR_MALLOC (sizeof (*pif));
memcpy (pif, pParams, sizeof (*pif));
piw = (struct Params_Image_Wrapper *)GTR_MALLOC (sizeof (*piw));
piw->pif = pif;
piw->tw = tw;
piw->parent_thread = Async_GetCurrentThread ();
piw->key = pParams->key; /* any child thread can unlock me */
XX_DMsg(DBG_NOT, ("Starting new image thread %lx key %d parent %lx\n",(unsigned)piw, piw->key, piw->parent_thread));
Async_StartThread (Fetch_Image_Wrapper_Async, (void *)piw, tw);
return STATE_DONE;
case STATE_ABORT:
default:
return STATE_DONE;
}
}
/*
** The job of this function is as a wrapper around
** Image_Fetch_Async() so I didn't have to modify it at all.
** This function simply makes sure that when Image_Fetch_Async()
** that information makes it back to the caller by means of
** decrementing tw->nOpenConnections and unblocking the thread
** of the caller. [note this function will only be started via
** Async_StartThread()]
**
**
** Note that I am using the Async_LockThread() function because
** the loadall images thread could be blocked with more gifs to
** display or it may have gone on its merry way and is blocked
** for some other reason, or it might not even exist any more.
*/
static int Fetch_Image_Wrapper_Async (struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_Wrapper *pParams =(struct Params_Image_Wrapper *)*ppInfo;
switch (nState)
{
case STATE_INIT:
tw->nOpenConnections++;
XX_DMsg(DBG_NOT, ("%lx calling image fetch \n",(unsigned)pParams));
Async_DoCall (Image_Fetch_Async, (void *)pParams->pif);
return STATE_OTHER;
case STATE_OTHER:
tw->nOpenConnections--;
XX_DMsg(DBG_NOT, ("%lx fetch returned Open:%d Thread %lx \n",(unsigned)pParams, tw->nOpenConnections, (unsigned) pParams->parent_thread));
if (Async_IsValidThread (pParams->parent_thread))
{
/*
** in case other thread was blocked waiting
** for a connection to be freed.
*/
XX_DMsg(DBG_NOT, ("%lx Unlocking thread %lx w/key %lx\n",(unsigned)pParams, (unsigned) pParams->parent_thread, pParams->key));
Async_UnlockThread (pParams->parent_thread, pParams->key);
}
return STATE_DONE;
case STATE_ABORT:
tw->nOpenConnections--;
return STATE_DONE;
}
}
#endif
#define STATE_FETCH_TRIEDLOAD (STATE_OTHER)
#define STATE_FETCH_GOTONE (STATE_OTHER+1)
int Image_Fetch_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_Fetch *pParams;
char buf[2048];
pParams = *ppInfo;
switch (nState)
{
case STATE_INIT:
XX_DMsg(DBG_IMAGE, ("Image_Fetch_Async: Called for %s\n", pParams->pImg->src));
if (!(pParams->pImg->flags & (IMG_NOTLOADED | IMG_PARTIAL)))
{
/* The image isn't marked as not loaded! */
XX_DMsg(DBG_IMAGE, ("Image not marked as not loaded (flags = 0x%x)\n", pParams->pImg->flags));
if (pParams->request)
{
HTRequest_delete(pParams->request);
pParams->request = NULL;
}
return STATE_DONE;
}
if (pParams->pImg->flags & IMG_PROGRESS)
{
XX_DMsg(DBG_IMAGE, ("Image is marked as in PROGRESS (flags = 0x%x)\n", pParams->pImg->flags));
if (pParams->request)
{
HTRequest_delete(pParams->request);
pParams->request = NULL;
}
return STATE_DONE;
}
pParams->pImg->flags |= IMG_PROGRESS;
pParams->request->destination = Dest_CreateDest(pParams->pImg->src);
XX_DMsg(DBG_IMAGE, ("Created dest 0x%x in request 0x%x\n", pParams->request->destination, pParams->request));
if (!pParams->request->destination)
{
pParams->pImg->flags = IMG_ERROR;
if (pParams->request)
{
HTRequest_delete(pParams->request);
pParams->request = NULL;
}
return STATE_DONE;
}
sprintf(buf, GTR_GetString(SID_INF_FETCHING_IMAGE_S), pParams->pImg->src);
WAIT_Push(tw, waitPartialInteract, buf);
pParams->request->referer = pParams->tw->w3doc->szActualURL;
{
struct Params_LoadAsync *pLoadParams;
pLoadParams = GTR_CALLOC(sizeof(*pLoadParams), 1);
if (pLoadParams)
{
pLoadParams->request = pParams->request;
pLoadParams->pStatus = &pParams->status;
Async_DoCall(HTLoadDocument_Async, pLoadParams);
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
pParams->pImg->flags = IMG_ERROR;
if (pParams->request)
{
HTRequest_delete(pParams->request);
pParams->request = NULL;
}
return STATE_ABORT;
}
}
return STATE_FETCH_TRIEDLOAD;
case STATE_FETCH_TRIEDLOAD:
WAIT_Pop(tw);
pParams->request->referer = NULL;
if (pParams->request->szLocalFileName)
{
GTR_FREE(pParams->request->szLocalFileName);
pParams->request->szLocalFileName = NULL;
}
if (pParams->status && pParams->pImg->width && pParams->pImg->height)
{
XX_DMsg(DBG_IMAGE, ("Fetching %s succeeded\n", pParams->pImg->src));
if (HT_CreateDeviceImageMap(tw, pParams->pImg))
{
ERR_ReportError(tw, SID_ERR_INVALID_IMAGE_FORMAT, NULL, NULL);
pParams->pImg->flags = IMG_ERROR;
}
}
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 (!pParams->pImg->flags || (pParams->pImg->flags & IMG_NOTLOADED))
{
RECT rUpdate;
HTList *cur;
wImageEleP p;
struct Mwin *mw;
pParams->pImg->flags = IMG_ERROR;
/* Inval the rect in each window this image is in */
if (pParams->pImg->llElements)
for (cur = pParams->pImg->llElements ; p = (wImageEleP) HTList_nextObject(cur) ; )
for (mw = Mlist; mw; mw = mw->next)
if (p->w3doc == mw->w3doc)
{
/* This image is in a window, so inval the image rect */
rUpdate = mw->w3doc->aElements[p->element].r;
GTR_OffsetRect(&rUpdate, -mw->offl, -mw->offt);
TW_UpdateRect(mw, &rUpdate);
}
}
}
XX_DMsg(DBG_IMAGE, ("Deleting dest 0x%x within request 0x%x within params 0x%x\n", pParams->request->destination, pParams->request, pParams));
Dest_DestroyDest(pParams->request->destination);
pParams->request->destination = NULL;
/* trial -dpg */
XX_DMsg(DBG_IMAGE, ("Deleting request 0x%x within params 0x%x\n", pParams->request, pParams));
HTRequest_delete(pParams->request);
pParams->request = NULL;
if (pParams->bOneImage == 2) /* is background */
{
struct ImageInfo *pImg = pParams->pImg;
pImg->flags &= ~IMG_PROGRESS;
#ifdef UNIX
if ( pImg->height < BGIMG_MIN_HEIGHT ||
pImg->width < BGIMG_MIN_WIDTH )
{
x_CreateBigBgImg (tw, pParams->pImg);
}
#endif
return STATE_DONE;
}
return STATE_FETCH_GOTONE;
case STATE_FETCH_GOTONE:
if (!(pParams->tw->w3doc->aElements[pParams->nEl].portion.img.myImage->flags & IMG_NOTLOADED))
{
if ( (pParams->bOneImage || gPrefs.ReformatHandling >= 2) &&
W3Doc_CheckForImageLoad(pParams->tw->w3doc) )
{
/* We're in "high-flicker" mode - reformat the document */
TW_Reformat(pParams->tw);
}
else
{
int i;
/* This is "no-flicker" mode - if the placeholder is the right size (because
we had image hints) just plop the image into the appropriate place(s) in
the document. */
for (i = pParams->nEl; i >= 0; i = pParams->tw->w3doc->aElements[i].next)
{
struct _element *pel;
pel = &(pParams->tw->w3doc->aElements[i]);
if (pel->type == ELE_IMAGE || pel->type == ELE_FORMIMAGE)
{
if (pel->portion.img.myImage == pParams->tw->w3doc->aElements[pParams->nEl].portion.img.myImage)
{
RECT rUpdate;
rUpdate = pel->r;
if (pel->iBorder > 0)
{
GTR_OffsetRect(&rUpdate, pel->iBorder, pel->iBorder);
}
if (!gPrefs.bProgressiveImageDisplay
&& pel->portion.img.height
&& pel->portion.img.width)
{
GTR_OffsetRect(&rUpdate, -pParams->tw->offl, -pParams->tw->offt);
TW_UpdateRect(pParams->tw, &rUpdate);
}
else
{
/* This means we never had valid hints */
if (!pel->portion.img.height || !pel->portion.img.width)
{
pel->portion.img.height = pel->portion.img.myImage->height;
pel->portion.img.width = pel->portion.img.myImage->width;
}
}
}
}
}
}
if (pParams->tw->w3doc->aElements[pParams->nEl].lFlags & ELEFLAG_USEMAP &&
pParams->tw->w3doc->aElements[pParams->nEl].portion.img.myMap->flags == MAP_NOTLOADED)
{
struct Params_Map_Fetch *pmf;
pmf = GTR_CALLOC(sizeof(*pmf), 1);
if (pmf)
{
pmf->pMap = pParams->tw->w3doc->aElements[pParams->nEl].portion.img.myMap;
Async_DoCall(Map_Fetch_Async, pmf);
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
pParams->pImg->flags = IMG_ERROR;
return STATE_ABORT;
}
}
}
pParams->pImg->flags &= ~IMG_PROGRESS;
return STATE_DONE;
case STATE_ABORT:
if (pParams->request)
{
XX_DMsg(DBG_IMAGE, ("ABORT Deleting dest 0x%x within request 0x%x within params 0x%x\n", pParams->request->destination, pParams->request, pParams));
Dest_DestroyDest(pParams->request->destination);
XX_DMsg(DBG_IMAGE, ("ABORT Deleting request 0x%x within params 0x%x\n", pParams->request, pParams));
HTRequest_delete(pParams->request);
}
/* turn of progress flag */
pParams->pImg->flags &= ~IMG_PROGRESS;
WAIT_Pop(tw);
return STATE_DONE;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
pParams->pImg->flags &= ~IMG_PROGRESS;
return STATE_DONE;
}
/* NOTE: this is only called on exit. From platform specific code.
* we should add a common exit routine that calls this function along
* with all other functions on exit.
* <Scott P. 7/29/95>
*/
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);
dispose_imageinfo(img);
}
Hash_FreeContents(&gImageCache);
}
/* 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_GETBACKGROUND (STATE_OTHER+2)
#define STATE_LOADALL_GOTBACKGROUND (STATE_OTHER+3)
#define STATE_LOADALL_FINISH_UP (STATE_OTHER+4)
/*
** Leave for menu option
*/
int Image_LoadAll_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_LoadAll *pParams;
pParams = *ppInfo;
switch (nState)
{
case STATE_INIT:
pParams->nEl = 0;
WAIT_Push(tw, waitPartialInteract, GTR_GetString(SID_INF_LOADING_IMAGES));
/* fall through */
case STATE_LOADALL_GETBACKGROUND:
if (pParams->tw->w3doc->piiBackground && (pParams->tw->w3doc->piiBackground->flags & (IMG_NOTLOADED | IMG_PARTIAL)))
{
struct Params_Image_Fetch *pif;
pif = GTR_CALLOC(sizeof(*pif), 1);
if (pif)
{
XX_DMsg(DBG_IMAGE, ("Create params 0x%x\n", pif));
pif->pImg = pParams->tw->w3doc->piiBackground;
pif->request=HTRequest_init(HTAtom_for("www/inline_image"));
if (pParams->bReload)
{
pif->request->iFlags |= HTREQ_RELOAD;
}
XX_DMsg(DBG_IMAGE, ("Created request 0x%x\n", pif->request));
pif->tw = pParams->tw;
pif->bOneImage = 2; /* code for background */
pif->nEl = 0;
/* If this is to be async, we need to move the GOTBACKGROUND
state into Image_Fetch_Async()
#ifdef FEATURE_ASYNC_IMAGES
if (gPrefs.nMaxConnections > 1)
Async_DoCall (Request_Fetch_Image_Async, pif);
else
#endif
*/
Async_DoCall (Image_Fetch_Async, pif);
return STATE_LOADALL_GOTBACKGROUND;
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return STATE_ABORT;
}
}
else
{
if (pParams->tw->w3doc->piiBackground)
{
return STATE_LOADALL_GOTBACKGROUND;
}
}
return STATE_LOADALL_GETNEXT;
case STATE_LOADALL_GOTBACKGROUND:
TW_InvalidateDocument(pParams->tw);
return STATE_LOADALL_GETNEXT;
case STATE_LOADALL_GETNEXT:
/* Find the next unloaded picture */
for ( ; pParams->nEl >= 0; pParams->nEl = pParams->tw->w3doc->aElements[pParams->nEl].next)
{
struct _element *pel;
pel = &pParams->tw->w3doc->aElements[pParams->nEl];
if ((pel->type == ELE_IMAGE || pel->type == ELE_FORMIMAGE)
&& (pel->portion.img.myImage && (pel->portion.img.myImage->flags & (IMG_NOTLOADED | IMG_PARTIAL))))
{
/* This is an unloaded picture. Do we want to load it? */
if (pParams->bLoad)
{
/* Yes, proceed */
#ifdef MAC
if (IsMemLow())
{
/* If we're this low on memory, we probably can't decompress and
store the image. We check this here rather than in STATE_INIT
so that
1) We don't give the error if there are no images to load
2) In case we run out of memory midway through the process.
*/
ERR_ReportError(tw, SID_ERR_COULD_NOT_LOAD_DOCUMENT_IMAGES, NULL, NULL);
WAIT_Pop(tw);
return STATE_DONE;
}
#endif
break;
}
}
}
if (pParams->nEl < 0)
return STATE_LOADALL_FINISH_UP;
/* OK, let's bring in this picture */
{
struct Params_Image_Fetch *pif;
pif = GTR_CALLOC(sizeof(*pif), 1);
if (pif)
{
XX_DMsg(DBG_IMAGE, ("Create params 0x%x\n", pif));
pif->pImg = pParams->tw->w3doc->aElements[pParams->nEl].portion.img.myImage;
pif->request=HTRequest_init(HTAtom_for("www/inline_image"));
if (pParams->bReload)
{
pif->request->iFlags |= HTREQ_RELOAD;
}
XX_DMsg(DBG_IMAGE, ("Created request 0x%x\n", pif->request));
pif->tw = pParams->tw;
pif->bOneImage = FALSE;
pif->nEl = pParams->nEl;
#ifdef FEATURE_ASYNC_IMAGES
/*
We don't do multi-connect when keepalive is active.
*/
if ((pParams->tw->cached_conn.type != CONN_HTTP) && (gPrefs.nMaxConnections > 1))
{
XX_DMsg(DBG_IMAGE, ("Starting a new connection for a fetch of %s\n", pif->pImg->src));
#ifdef FEATURE_SOCKS_LOW_LEVEL
/** For now if SOCKS is being used use only
one connection
**/
if (Dest_CheckSocksProxy(pif->pImg->src))
Async_DoCall (Image_Fetch_Async, pif);
else
#endif /** FEATURE_SOCKS_LOW_LEVEL **/
Async_DoCall (Request_Fetch_Image_Async, pif);
}
else
#endif
{
Async_DoCall (Image_Fetch_Async, pif);
}
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return STATE_ABORT;
}
}
pParams->nEl = pParams->tw->w3doc->aElements[pParams->nEl].next;
/* return STATE_LOADALL_GOTONE; */
return STATE_LOADALL_GETNEXT;
case STATE_LOADALL_FINISH_UP:
{
if (tw->nOpenConnections > 0)/* wait for all images to finish */
{
/* tw is THE key for multiple connections, so
** I cheat here and use it. Each of the
** currently loading images will re-awaken me.
*/
Async_LockThread (Async_GetCurrentThread(), (TKey)pParams->tw);
return STATE_LOADALL_FINISH_UP;
}
/* There are no more unloaded pictures */
pParams->tw->w3doc->bHasMissingImages = W3Doc_HasMissingImages(pParams->tw->w3doc);
WAIT_Pop(tw);
return STATE_DONE;
}
case STATE_ABORT:
pParams->tw->w3doc->bHasMissingImages = W3Doc_HasMissingImages(pParams->tw->w3doc);
WAIT_Pop(tw);
return STATE_DONE;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
return STATE_DONE;
}
/*
** Leave for right mouse click
*/
#define STATE_LOADALL_GOTIT (STATE_OTHER)
int Image_LoadOneImage_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_Image_LoadAll *pParams;
pParams = *ppInfo;
switch (nState)
{
case STATE_INIT:
WAIT_Push(tw, waitPartialInteract, GTR_GetString(SID_INF_LOADING_IMAGES));
/* OK, let's bring in this picture */
{
struct Params_Image_Fetch *pif;
pif = GTR_CALLOC(sizeof(*pif), 1);
if (pif)
{
XX_DMsg(DBG_IMAGE, ("Create params 0x%x\n", pif));
pif->pImg = pParams->tw->w3doc->aElements[pParams->nEl].portion.img.myImage;
pif->request=HTRequest_init(HTAtom_for("www/inline_image"));
if (pParams->bReload)
{
pif->request->iFlags |= HTREQ_RELOAD;
}
XX_DMsg(DBG_IMAGE, ("Created request 0x%x\n", pif->request));
pif->tw = pParams->tw;
pif->bOneImage = TRUE;
pif->nEl = pParams->nEl;
Async_DoCall(Image_Fetch_Async, pif);
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return STATE_ABORT;
}
}
return STATE_LOADALL_GOTIT;
case STATE_LOADALL_GOTIT:
#if 0
if (!(pParams->tw->w3doc->aElements[pParams->nEl].myImage->flags & IMG_NOTLOADED))
{
if (W3Doc_CheckForImageLoad(pParams->tw->w3doc))
{
TW_Reformat(pParams->tw);
}
else
{
RECT rUpdate;
rUpdate = pParams->tw->w3doc->aElements[pParams->nEl].r;
OffsetRect(&rUpdate, -pParams->tw->offl, -pParams->tw->offt);
TW_UpdateRect(pParams->tw, &rUpdate);
}
if (pParams->tw->w3doc->aElements[pParams->nEl].lFlags & ELEFLAG_USEMAP &&
pParams->tw->w3doc->aElements[pParams->nEl].myMap->flags == MAP_NOTLOADED)
{
struct Params_Map_Fetch *pmf;
pmf = GTR_CALLOC(sizeof(*pmf), 1);
if (pmf)
{
pmf->pMap = pParams->tw->w3doc->aElements[pParams->nEl].myMap;
Async_DoCall(Map_Fetch_Async, pmf);
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return STATE_ABORT;
}
}
}
else
{
RECT rUpdate;
rUpdate = pParams->tw->w3doc->aElements[pParams->nEl].r;
OffsetRect(&rUpdate, -pParams->tw->offl, -pParams->tw->offt);
TW_UpdateRect(pParams->tw, &rUpdate);
}
#endif /* 0 */
pParams->tw->w3doc->bHasMissingImages = W3Doc_HasMissingImages(pParams->tw->w3doc);
WAIT_Pop(tw);
if (!pParams->tw->w3doc->bHasMissingImages)
TW_UpdateTBar(tw);
return STATE_DONE;
case STATE_ABORT:
pParams->tw->w3doc->bHasMissingImages = W3Doc_HasMissingImages(pParams->tw->w3doc);
WAIT_Pop(tw);
return STATE_DONE;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
return STATE_DONE;
}
/* Remove all images in a document and replace them with placeholders */
BOOL Image_NukeImages(struct _www *pdoc, BOOL bNukeMaps)
{
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 (!(pdoc->aElements[n].portion.img.myImage->flags & (IMG_NOTLOADED | IMG_BUILTIN)))
{
struct ImageInfo *myImage = pdoc->aElements[n].portion.img.myImage;
/* If this is merely a placeholder, there may not be any image to delete */
x_DisposeImage (myImage);
myImage->width = myImage->height = 0;
myImage->flags = IMG_NOTLOADED;
/* Note that myImage->src is carefully left intact. */
bSomethingNuked = TRUE;
}
if (bNukeMaps && pdoc->aElements[n].lFlags & ELEFLAG_USEMAP)
{
Map_Unload (pdoc->aElements[n].portion.img.myMap);
}
}
}
/* TODO: Make it invalid from first image down.
if (bSomethingNuked)
pdoc->bNeedsReformat = TRUE;
*/
return bSomethingNuked;
}
/*
** Add an element to the ImageInfo's list of referencing elements
**
** returns 0 or -1 on failure
*/
int Image_AddElement (struct ImageInfo *myImage,
struct _www *w3doc, int element)
{
wImageEleP ie;
if (!myImage->llElements)
{
myImage->llElements = HTList_new ();
}
if (!myImage->llElements)
return -1;
ie = (wImageEleP) GTR_MALLOC (sizeof (*ie));
if (!ie)
{
return -1;
}
ie->w3doc = w3doc;
ie->element = element;
HTList_addObject (myImage->llElements, (void *)ie);
#ifdef ELEM_DEBUG
{
HTList *cur;
wImageEleP p;
/*DEBUG*/
fprintf (stderr, "Image_AddElement Called\n");
for (cur = myImage->llElements ; p = (wImageEleP) HTList_nextObject(cur) ; )
{
fprintf (stderr, " > w3doc refcount: %d Elem %d\n", p->w3doc->refCount, p->element);
}
}
#endif
return 0;
}
/*
** Remove an element from the ImageInfo's list of referencing elements
**
** returns 0 or -1 on failure
*/
int Image_DeleteElement (struct ImageInfo *myImage,
struct _www *w3doc, int element)
{
HTList *cur;
wImageEleP p;
if (!myImage->llElements)
return -1;
for (cur = myImage->llElements ; p = (wImageEleP) HTList_nextObject(cur) ; )
{
if (p->w3doc == w3doc && p->element == element)
{
HTList_removeObject (myImage->llElements, p);
GTR_FREE (p);
myImage->refCount--;
return 0;
}
}
#ifdef ELEM_DEBUG
/*DEBUG*/ fprintf (stderr, "Image_DeleteElement Called\n");
for (cur = myImage->llElements ; p = (wImageEleP) HTList_nextObject(cur) ; )
{
fprintf (stderr, " > w3doc refcount: %d Elem %d\n", p->w3doc->refCount, p->element);
}
#endif
return -1;
}