in the usual place at image.cpp. only RDF cases are handled here. git-svn-id: svn://10.0.0.236/trunk@11651 18797224-902f-48f8-a5cc-f745e15eee43
508 lines
12 KiB
C++
508 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
* the License for the specific language governing rights and limitations
|
|
* under the License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
|
* Netscape Communications Corporation. All Rights Reserved.
|
|
*/
|
|
/*
|
|
RDFImage.cpp - Aurora Image loading class
|
|
Created: Radha Kulkarni <radha@netscape.com>, 06-29-98
|
|
*/
|
|
|
|
#include "RDFImage.h"
|
|
#include "ViewGlue.h"
|
|
#include "xfe.h"
|
|
#include "il_util.h"
|
|
|
|
#ifdef DEBUG_radha
|
|
#define D(x) x
|
|
#else
|
|
#define D(x)
|
|
#endif
|
|
|
|
#if 0
|
|
extern "C"
|
|
{
|
|
void DisplayPixmap(MWContext *, IL_Pixmap *, IL_Pixmap *);
|
|
void NewPixmap(MWContext *, IL_Pixmap * image, PRBool mask);
|
|
void ImageComplete(MWContext *, IL_Pixmap * image);
|
|
void fe_load_default_font(MWContext *context);
|
|
};
|
|
#endif
|
|
|
|
int XFE_RDFImage::refCount = 0;
|
|
int XFE_RDFImage::m_numRDFImagesLoaded = 0;
|
|
RDFImageList * XFE_RDFImage::RDFImagesCache = (RDFImageList *) NULL;
|
|
// Max number of images in cache - to be replaced with very clever hash table
|
|
unsigned int XFE_RDFImage::MaxRdfImages = 30;
|
|
//unsigned int XFE_RDFImage::ImageListIncrSize = 20;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// Initialize the images list. This s'd someday be a hash list
|
|
void
|
|
XFE_RDFImage::imageCacheInitialize()
|
|
{
|
|
|
|
/* The array way of indexing the cache only works for now when
|
|
* NavCenterView is the only client of RDFImage. This w'd break or
|
|
* corrupt if more clients come in for RDFImage. The cache needs
|
|
* to be a Doubly linked list. That will happen in the next round
|
|
* of changes to RDFImage.
|
|
*/
|
|
if (RDFImagesCache == NULL)
|
|
{
|
|
m_numRDFImagesLoaded = 0;
|
|
RDFImagesCache = (RDFImageList *) XP_CALLOC(MaxRdfImages, sizeof(RDFImageList));
|
|
}
|
|
}
|
|
|
|
XFE_RDFImage::XFE_RDFImage(XFE_Component * frame,
|
|
void * requestedObj,
|
|
char * imageURL,
|
|
fe_colormap * cmap,
|
|
Widget baseWidget)
|
|
: XFE_Image(frame, imageURL, cmap, baseWidget)
|
|
{
|
|
|
|
// Initializations
|
|
pairCount = 0;
|
|
completeCallback = (completeCallbackPtr) NULL;
|
|
callbackData = (void *) NULL;
|
|
|
|
|
|
// Make sure the cache is up and running.
|
|
// XFE_RDFImage::imageCacheInitialize();
|
|
|
|
|
|
if (cxtInitSucceeded)
|
|
addListener(requestedObj, baseWidget, imageURL);
|
|
|
|
}
|
|
|
|
|
|
XFE_RDFImage::~XFE_RDFImage()
|
|
{
|
|
int i = 0, j = 0;
|
|
|
|
|
|
// Delete the bad image if m_numRDFImagesLoaded = 0
|
|
if (m_numRDFImagesLoaded == 0)
|
|
{
|
|
D(printf("Need to delete the bad image here \n");)
|
|
XP_FREE(RDFImagesCache);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Set the callback for the requestor */
|
|
void
|
|
XFE_RDFImage::setCompleteCallback(completeCallbackPtr callback, void * client_data)
|
|
{
|
|
completeCallback = callback;
|
|
callbackData = client_data;
|
|
|
|
}
|
|
|
|
|
|
/* Image library callback with the image pixmap and mask. The mask
|
|
* mask part is not working right now.
|
|
*/
|
|
void
|
|
XFE_RDFImage::RDFDisplayPixmap(IL_Pixmap * image, IL_Pixmap * mask, PRInt32 width, PRInt32 height)
|
|
{
|
|
m_image = image;
|
|
m_mask = mask;
|
|
imageWidth = width;
|
|
imageHeight = height;
|
|
pairCount++;
|
|
|
|
if (!completelyLoaded)
|
|
{
|
|
callbackClientData * client_data = XP_NEW_ZAP(callbackClientData);
|
|
client_data->widget = (Widget)callbackData;
|
|
client_data->image = getPixmap();
|
|
client_data->mask = getMask();
|
|
/*
|
|
client_data->width = width;
|
|
client_data->height = height;
|
|
*/
|
|
completelyLoaded = True;
|
|
if (isrequestorAlive(client_data->widget))
|
|
(*completeCallback)(client_data);
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Image library callback */
|
|
void
|
|
XFE_RDFImage::RDFNewPixmap(IL_Pixmap * image, PRBool isMask)
|
|
{
|
|
if (isMask)
|
|
m_mask = image;
|
|
else m_image = image;
|
|
|
|
}
|
|
|
|
/* This method is really useful when different images are
|
|
* requested. If a request for the same image is made
|
|
* in immediate succession like we do right now in NavCenterView.cpp
|
|
* this doesn't work. So commented off for now
|
|
*/
|
|
|
|
|
|
void
|
|
XFE_RDFImage::RDFImageComplete(IL_Pixmap * image)
|
|
{
|
|
#ifdef UNDEF
|
|
// Will get a call for both the mask and for the image.
|
|
if (m_image && m_mask)
|
|
{
|
|
if (pairCount == 2)
|
|
if (isrequestorAlive)
|
|
(*completeCallback)(getPixmap(), getMask(), callbackData);
|
|
else
|
|
pairCount++;
|
|
}
|
|
else if (m_image)
|
|
{
|
|
// We have no mask.
|
|
if (isrequestorAlive)
|
|
(*completeCallback)(getPixmap(), getMask(), callbackData);
|
|
}
|
|
#endif /* UNDEF */
|
|
|
|
}
|
|
|
|
/* returns if the image has been completely loaded */
|
|
PRBool
|
|
XFE_RDFImage::isImageLoaded(void)
|
|
{
|
|
return (completelyLoaded);
|
|
|
|
}
|
|
|
|
|
|
/* return the image pixmap */
|
|
Pixmap
|
|
XFE_RDFImage::getPixmap(void)
|
|
{
|
|
if (m_image && m_image->client_data)
|
|
return (Pixmap)(((fe_PixmapClientData *)(m_image->client_data))->pixmap);
|
|
return (Pixmap)NULL;
|
|
}
|
|
|
|
/* Return the image mask */
|
|
Pixmap
|
|
XFE_RDFImage::getMask(void)
|
|
{
|
|
if (m_mask && m_mask->client_data)
|
|
return (Pixmap)(((fe_PixmapClientData *)(m_mask->client_data))->pixmap);
|
|
return (Pixmap)NULL;
|
|
|
|
}
|
|
|
|
/* Get image width */
|
|
PRInt32
|
|
XFE_RDFImage::getImageWidth(void)
|
|
{
|
|
return(imageWidth);
|
|
}
|
|
|
|
/* Get image height */
|
|
PRInt32
|
|
XFE_RDFImage::getImageHeight(void)
|
|
{
|
|
return(imageHeight);
|
|
}
|
|
|
|
|
|
/* Call NET_GetURL() to fetch the image */
|
|
void
|
|
XFE_RDFImage::loadImage(void)
|
|
{
|
|
if (cxtInitSucceeded)
|
|
NET_GetURL(NET_CreateURLStruct(m_urlString, NET_DONT_RELOAD),
|
|
FO_CACHE_AND_PRESENT, m_imageContext,
|
|
XFE_Image::getURLExit_cb);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Given a imageURL, this method goes thro' the cache and checks if
|
|
* is already available. If available, it returns a handle to the
|
|
* RDFImageobject, that holds the pixmap for the image.
|
|
* The lookup is currently a simple strcmp. But it can be replaced by
|
|
* a better system.
|
|
*/
|
|
|
|
XFE_RDFImage *
|
|
XFE_RDFImage::isImageAvailable(char * imageURL)
|
|
{
|
|
RDFImageList * ptr = RDFImagesCache;
|
|
if (!ptr)
|
|
return (XFE_RDFImage *) NULL;
|
|
do
|
|
{
|
|
|
|
if ((!XP_STRCMP(imageURL, ptr->imageURL))) {
|
|
/* If the RDFImage object related to the url
|
|
* is still around, and the pixmap has been completely loaded,
|
|
* return handle to the RDFImage object.
|
|
*/
|
|
|
|
if (ptr->obj && ((ptr->obj)->isImageLoaded()))
|
|
return (ptr->obj);
|
|
else
|
|
/* The image URL is in the cache,but the image is not ready yet */
|
|
return((XFE_RDFImage *)NULL);
|
|
}
|
|
ptr = ptr->next;
|
|
} while (ptr != RDFImagesCache);
|
|
return (XFE_RDFImage *)NULL;
|
|
|
|
#ifdef UNDEF
|
|
int i = 0;
|
|
|
|
for (i = 0; i< m_numRDFImagesLoaded; i++)
|
|
{
|
|
if (!XP_STRCMP(imageURL, RDFImagesCache[i].imageURL))
|
|
{
|
|
/* If the RDFImage object related to the url
|
|
* is still around, and the pixmap has been completely loaded,
|
|
* return handle to the RDFImage object.
|
|
*/
|
|
|
|
if (RDFImagesCache[i].obj && ((RDFImagesCache[i].obj)->isImageLoaded()))
|
|
return (RDFImagesCache[i].obj);
|
|
}
|
|
} // for
|
|
|
|
return (XFE_RDFImage * ) NULL;
|
|
#endif /* UNDEF */
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Remove a widget from the listener list.
|
|
* This s'd be called by the destroy callback of the
|
|
* widget that requested the image. This is to take care of cases
|
|
* where a specific widget associated with the image goes away, but the
|
|
* class that it originated from is not gone. This
|
|
* works with isRequestorAlive()
|
|
*/
|
|
|
|
void
|
|
XFE_RDFImage::removeListener(Widget w)
|
|
{
|
|
|
|
RDFImageList * ptr = RDFImagesCache;
|
|
if (!ptr)
|
|
return;
|
|
do
|
|
{
|
|
if (ptr->widget == w) {
|
|
ptr->widget = NULL;
|
|
}
|
|
ptr = ptr->next;
|
|
} while (ptr != RDFImagesCache);
|
|
|
|
}
|
|
|
|
/*
|
|
* This method s'd be called from the requesting object's destructor.
|
|
* It basically goes through the cache and deletes all the RDFImage
|
|
* objects that the requestor had requested.
|
|
*/
|
|
|
|
void
|
|
XFE_RDFImage::removeListener(void * obj)
|
|
{
|
|
RDFImageList * ptr = RDFImagesCache, *p;
|
|
int cnt = m_numRDFImagesLoaded;
|
|
if (!ptr)
|
|
return;
|
|
|
|
do
|
|
{
|
|
if (ptr->requestedObj == obj) {
|
|
removeListener(ptr);
|
|
// set the pointers properly
|
|
ptr->prev->next = ptr->next;
|
|
ptr->next->prev = ptr->prev;
|
|
p = ptr->next;
|
|
if (ptr == RDFImagesCache)
|
|
RDFImagesCache = ptr->next;
|
|
XP_FREE(ptr);
|
|
ptr = p;
|
|
}
|
|
else
|
|
ptr = ptr->next;
|
|
cnt--;
|
|
} while (/* ptr->next != RDFImagesCache */ cnt != 0) ;
|
|
|
|
} /* removeListener */
|
|
|
|
|
|
/* free and reset an element in the cache */
|
|
void
|
|
XFE_RDFImage::removeListener(RDFImageList * ptr) {
|
|
|
|
// free the string
|
|
if (ptr->imageURL) {
|
|
free(ptr->imageURL);
|
|
}
|
|
|
|
// Set the widget pointer to NULL
|
|
ptr->widget = NULL;
|
|
|
|
/* Delete the RDFImage object */
|
|
|
|
if (ptr->obj) {
|
|
delete(ptr->obj);
|
|
}
|
|
|
|
// reset the requestor's pointer
|
|
ptr->requestedObj = (void *)NULL;
|
|
|
|
m_numRDFImagesLoaded--;
|
|
|
|
} /* removeListener */
|
|
|
|
|
|
/* Add a new image to the cache */
|
|
void
|
|
XFE_RDFImage::addListener(void * requestedObj, Widget w, char * imageURL)
|
|
{
|
|
|
|
RDFImageList * ptr = XP_NEW_ZAP(RDFImageList);
|
|
|
|
if (m_numRDFImagesLoaded == 0) {
|
|
/* First entry */
|
|
RDFImagesCache = ptr;
|
|
}
|
|
ptr->next = RDFImagesCache;
|
|
ptr->prev = ((m_numRDFImagesLoaded == 0) ? RDFImagesCache : RDFImagesCache->prev);
|
|
(ptr->prev)->next = ptr;
|
|
RDFImagesCache->prev = ptr;
|
|
|
|
ptr->obj = this;
|
|
ptr->requestedObj = requestedObj;
|
|
ptr->widget = w;
|
|
ptr->imageURL = (char *)XP_ALLOC(sizeof(char) * (strlen(imageURL) + 1));
|
|
strncpy(ptr->imageURL, imageURL, strlen(imageURL));
|
|
m_numRDFImagesLoaded++;
|
|
|
|
|
|
#ifdef UNDEF
|
|
/* Go through the cache and see if there are any existing
|
|
* space that is available.
|
|
*/
|
|
for (i=0; i<m_numRDFImagesLoaded; i++) {
|
|
if (RDFImagesCache[i].isSpaceAvailable) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (m_numRDFImagesLoaded == MaxRdfImages) {
|
|
/* The array is full. realloc */
|
|
RDFImagesCache = (RDFImageList *) XP_REALLOC(RDFImagesCache, ((MaxRdfImages + ImageListIncrSize)*sizeof(RDFImageList)));
|
|
MaxRdfImages +=ImageListIncrSize;
|
|
|
|
}
|
|
if (m_numRDFImagesLoaded < MaxRdfImages) {
|
|
RDFImagesCache[i].obj = this;
|
|
RDFImagesCache[i].requestedObj = requestedObj;
|
|
RDFImagesCache[i].widget = w;
|
|
RDFImagesCache[i].imageURL = (char *)XP_ALLOC(sizeof(char) * (strlen(imageURL) + 1));
|
|
strncpy(RDFImagesCache[i].imageURL, imageURL, strlen(imageURL));
|
|
RDFImagesCache[i].isSpaceAvailable = False;
|
|
m_numRDFImagesLoaded++;
|
|
}
|
|
#endif /* UNDEF */
|
|
|
|
} /* addListener */
|
|
|
|
|
|
/*
|
|
* This is called by RDFDisplayPixmap(),
|
|
* to make sure that the widget that
|
|
* requested the image is still around
|
|
*/
|
|
PRBool
|
|
XFE_RDFImage::isrequestorAlive(Widget w)
|
|
{
|
|
RDFImageList * ptr = RDFImagesCache;
|
|
|
|
if (!ptr)
|
|
return(False);
|
|
do
|
|
{
|
|
if (ptr->widget == w) {
|
|
return(True);
|
|
}
|
|
ptr = ptr->next;
|
|
} while (ptr != RDFImagesCache);
|
|
return (False);
|
|
|
|
#ifdef UNDEF
|
|
for(int i = 0; i<m_numRDFImagesLoaded; i++) {
|
|
if (RDFImagesCache[i].widget == w)
|
|
return (True);
|
|
}
|
|
return (False);
|
|
#endif /* UNDEF */
|
|
|
|
}
|
|
|
|
/*
|
|
* Given a widget id, get a handle to the corresponding RDFImage object
|
|
* This is used by the Image library callbacks, for whom the widget id
|
|
* is the only link to the XFE world
|
|
*/
|
|
|
|
XFE_RDFImage *
|
|
XFE_RDFImage::getRDFImageObject(Widget w)
|
|
{
|
|
RDFImageList * ptr = RDFImagesCache;
|
|
if (!ptr)
|
|
return(XFE_RDFImage *) NULL;
|
|
do
|
|
{
|
|
if (ptr->widget == w) {
|
|
return(ptr->obj);
|
|
}
|
|
ptr = ptr->next;
|
|
} while (ptr != RDFImagesCache);
|
|
return (XFE_RDFImage *)NULL;
|
|
|
|
#ifdef UNDEF
|
|
for(int i = 0; i<m_numRDFImagesLoaded; i++) {
|
|
if (RDFImagesCache[i].widget == w)
|
|
return (RDFImagesCache[i].obj);
|
|
}
|
|
return (XFE_RDFImage *) NULL;
|
|
#endif /* UNDEF */
|
|
}
|
|
|
|
|
|
|