/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsImageRequest.h" #include "nsIImageGroup.h" #include "nsIImageObserver.h" #include "nsIImage.h" #include "nsVoidArray.h" #include "nsRect.h" #include "nsImageNet.h" static NS_DEFINE_IID(kIImageRequestIID, NS_IIMAGEREQUEST_IID); static void ns_observer_proc (XP_Observable aSource, XP_ObservableMsg aMsg, void* aMsgData, void* aClosure) { ImageRequestImpl *image_request = (ImageRequestImpl *)aClosure; IL_MessageData *message_data = (IL_MessageData *)aMsgData; nsVoidArray *observer_list = image_request->GetObservers(); nsIImage *image = nsnull; // IL_ImageReq *il_image_req = image_request->GetImageRequest(); IL_ImageReq *il_image_req = (IL_ImageReq *)aSource; if (il_image_req != nsnull) { IL_Pixmap *pixmap = IL_GetImagePixmap(il_image_req); if (pixmap != nsnull) { image = (nsIImage *)pixmap->client_data; } } if (observer_list != nsnull) { PRInt32 i, count = observer_list->Count(); nsIImageRequestObserver *observer; for (i = 0; i < count; i++) { observer = (nsIImageRequestObserver *)observer_list->ElementAt(i); if (observer != nsnull) { switch (aMsg) { case IL_START_URL: observer->Notify(image_request, image, nsImageNotification_kStartURL, 0, 0, nsnull); break; case IL_DESCRIPTION: observer->Notify(image_request, image, nsImageNotification_kDescription, 0, 0, message_data->description); break; case IL_DIMENSIONS: observer->Notify(image_request, image, nsImageNotification_kDimensions, (PRInt32)message_data->width, (PRInt32)message_data->height, nsnull); break; case IL_IS_TRANSPARENT: observer->Notify(image_request, image, nsImageNotification_kIsTransparent, 0, 0, nsnull); break; case IL_PIXMAP_UPDATE: { nsRect rect(message_data->update_rect.x_origin, message_data->update_rect.y_origin, message_data->update_rect.width, message_data->update_rect.height); observer->Notify(image_request, image, nsImageNotification_kPixmapUpdate, 0, 0, &rect); } break; case IL_FRAME_COMPLETE: observer->Notify(image_request, image, nsImageNotification_kFrameComplete, 0, 0, nsnull); break; case IL_PROGRESS: observer->Notify(image_request, image, nsImageNotification_kProgress, message_data->percent_progress, 0, nsnull); break; case IL_IMAGE_COMPLETE: observer->Notify(image_request, image, nsImageNotification_kImageComplete, 0, 0, nsnull); break; case IL_STOP_URL: observer->Notify(image_request, image, nsImageNotification_kStopURL, 0, 0, nsnull); break; case IL_IMAGE_DESTROYED: image_request->SetImageRequest(nsnull); observer->Notify(image_request, image, nsImageNotification_kImageDestroyed, 0, 0, nsnull); break; case IL_ABORTED: observer->Notify(image_request, image, nsImageNotification_kAborted, 0, 0, nsnull); break; case IL_INTERNAL_IMAGE: observer->Notify(image_request, image, nsImageNotification_kInternalImage, 0, 0, nsnull); break; case IL_NOT_IN_CACHE: observer->NotifyError(image_request, nsImageError_kNotInCache); break; case IL_ERROR_NO_DATA: observer->NotifyError(image_request, nsImageError_kNoData); break; case IL_ERROR_IMAGE_DATA_CORRUPT: observer->NotifyError(image_request, nsImageError_kImageDataCorrupt); break; case IL_ERROR_IMAGE_DATA_TRUNCATED: observer->NotifyError(image_request, nsImageError_kImageDataTruncated); break; case IL_ERROR_IMAGE_DATA_ILLEGAL: observer->NotifyError(image_request, nsImageError_kImageDataIllegal); break; case IL_ERROR_INTERNAL: observer->NotifyError(image_request, nsImageError_kInternalError); break; } } } } /* * If the IL_ImageReq is being destroyed, clear the reference held by * the nsImageRequestImpl... * * This will prevent a dangling reference in cases where the image group * is destroyed before the image request... */ if ((IL_IMAGE_DESTROYED == aMsg) && (nsnull != image_request)) { image_request->SetImageRequest(nsnull); image_request->ImageDestroyed(); } } ImageRequestImpl::ImageRequestImpl() { } ImageRequestImpl::~ImageRequestImpl() { // Delete the list of observers, and release the reference to the image // request observer object if (nsnull != mObservers) { for (PRInt32 cnt = 0; cnt < mObservers->Count(); cnt++) { nsIImageRequestObserver* observer; observer = (nsIImageRequestObserver*)mObservers->ElementAt(cnt); NS_IF_RELEASE(observer); mObservers->ReplaceElementAt(nsnull, cnt); } delete mObservers; } // XP Observer list destroyed by the image library } nsresult ImageRequestImpl::Init(IL_GroupContext *aGroupContext, const char* aUrl, nsIImageRequestObserver *aObserver, const nscolor* aBackgroundColor, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aFlags, ilINetContext* aNetContext) { NS_PRECONDITION(nsnull != aGroupContext, "null group context"); NS_PRECONDITION(nsnull != aUrl, "null URL"); NS_Error status; IL_IRGB bgcolor; PRUint32 flags; mGroupContext = aGroupContext; if (nsnull != aObserver) { if (AddObserver(aObserver) == PR_FALSE) { return NS_ERROR_OUT_OF_MEMORY; } } status = XP_NewObserverList(NULL, &mXPObserver); if (status < 0) { return NS_ERROR_OUT_OF_MEMORY; } status = XP_AddObserver(mXPObserver, ns_observer_proc, (void *)this); if (status < 0) { XP_DisposeObserverList(mXPObserver); mXPObserver = nsnull; return NS_ERROR_OUT_OF_MEMORY; } if (nsnull != aBackgroundColor) { bgcolor.red = NS_GET_R(*aBackgroundColor); bgcolor.green = NS_GET_G(*aBackgroundColor); bgcolor.blue = NS_GET_B(*aBackgroundColor); } flags = ((aFlags & IL_HIGH_PRIORITY) ? nsImageLoadFlags_kHighPriority : 0) | ((aFlags & IL_STICKY) ? nsImageLoadFlags_kSticky : 0) | ((aFlags & IL_BYPASS_CACHE) ? nsImageLoadFlags_kBypassCache : 0) | ((aFlags & IL_ONLY_FROM_CACHE) ? nsImageLoadFlags_kOnlyFromCache : 0); mImageReq = IL_GetImage(aUrl, aGroupContext, mXPObserver, nsnull == aBackgroundColor ? nsnull : &bgcolor, aWidth, aHeight, flags, (void *)aNetContext); if (mImageReq == nsnull) { XP_DisposeObserverList(mXPObserver); mXPObserver = nsnull; return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } NS_IMPL_ADDREF(ImageRequestImpl) NS_IMPL_QUERY_INTERFACE(ImageRequestImpl, kIImageRequestIID) nsrefcnt ImageRequestImpl::Release(void) { if (--mRefCnt == 0) { if (mXPObserver) { // Make sure dangling reference to this object goes away XP_RemoveObserver(mXPObserver, ns_observer_proc, (void*)this); } if (mImageReq) { IL_DestroyImage(mImageReq); } NS_DELETEXPCOM(this); return 0; } return mRefCnt; } nsIImage* ImageRequestImpl::GetImage() { if (mImageReq != nsnull) { IL_Pixmap *pixmap = IL_GetImagePixmap(mImageReq); if (pixmap != nsnull) { nsIImage *image = (nsIImage *)pixmap->client_data; if (image != nsnull) { NS_ADDREF(image); return image; } } } return nsnull; } void ImageRequestImpl::GetNaturalDimensions(PRUint32 *aWidth, PRUint32 *aHeight) { if (mImageReq != nsnull) { IL_GetNaturalDimensions(mImageReq, (int *)aWidth, (int *)aHeight); } else { *aWidth = 0; *aHeight = 0; } } PRBool ImageRequestImpl::AddObserver(nsIImageRequestObserver *aObserver) { if (aObserver == nsnull) { return PR_FALSE; } if (mObservers == nsnull) { mObservers = new nsVoidArray(); if (mObservers == nsnull) { return PR_FALSE; } } NS_ADDREF(aObserver); mObservers->AppendElement((void *)aObserver); return PR_TRUE; } PRBool ImageRequestImpl::RemoveObserver(nsIImageRequestObserver *aObserver) { PRBool ret; if (aObserver == nsnull || mObservers == nsnull) { return PR_FALSE; } ret = mObservers->RemoveElement((void *)aObserver); if (ret == PR_TRUE) { NS_RELEASE(aObserver); } return ret; } void ImageRequestImpl::Interrupt() { if (mImageReq != nsnull) { IL_InterruptRequest(mImageReq); } } void ImageRequestImpl::ImageDestroyed() { if (mXPObserver) { // Make sure dangling reference to this object goes // away; this is just in case the image library changes // and holds onto the observer list after destroying the // image. XP_RemoveObserver(mXPObserver, ns_observer_proc, (void*)this); mXPObserver = nsnull; } }