least one pixmap update notification git-svn-id: svn://10.0.0.236/trunk@6891 18797224-902f-48f8-a5cc-f745e15eee43
392 lines
11 KiB
C++
392 lines
11 KiB
C++
/* -*- 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 "nsFrameImageLoader.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIViewManager.h"
|
|
#include "nsIView.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsIURL.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIImageGroup.h"
|
|
#include "nsIImageRequest.h"
|
|
#include "nsString.h"
|
|
#include "prlog.h"
|
|
#include "nsISizeOfHandler.h"
|
|
#include "nsIStyleContext.h"
|
|
|
|
static NS_DEFINE_IID(kIFrameImageLoaderIID, NS_IFRAME_IMAGE_LOADER_IID);
|
|
static NS_DEFINE_IID(kIImageRequestObserverIID, NS_IIMAGEREQUESTOBSERVER_IID);
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
|
|
static PRLogModuleInfo* gFrameImageLoaderLMI;
|
|
|
|
NS_LAYOUT nsresult
|
|
NS_NewFrameImageLoader(nsIFrameImageLoader** aInstancePtrResult)
|
|
{
|
|
nsFrameImageLoader* it = new nsFrameImageLoader();
|
|
if (nsnull == it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return it->QueryInterface(kIFrameImageLoaderIID,
|
|
(void**) aInstancePtrResult);
|
|
}
|
|
|
|
nsFrameImageLoader::nsFrameImageLoader()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mImage = nsnull;
|
|
mSize.width = 0;
|
|
mSize.height = 0;
|
|
mError = (nsImageError) -1;
|
|
mTargetFrame = nsnull;
|
|
mPresContext = nsnull;
|
|
mImageRequest = nsnull;
|
|
mImageLoadStatus = NS_IMAGE_LOAD_STATUS_NONE;
|
|
#ifdef NS_DEBUG
|
|
if (nsnull == gFrameImageLoaderLMI) {
|
|
gFrameImageLoaderLMI = PR_NewLogModule("frameimageloader");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
nsFrameImageLoader::~nsFrameImageLoader()
|
|
{
|
|
NS_IF_RELEASE(mImageRequest);
|
|
NS_IF_RELEASE(mPresContext);
|
|
}
|
|
|
|
NS_IMPL_ADDREF(nsFrameImageLoader)
|
|
|
|
NS_IMPL_RELEASE(nsFrameImageLoader)
|
|
|
|
NS_METHOD
|
|
nsFrameImageLoader::QueryInterface(REFNSIID aIID,
|
|
void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(kIImageRequestObserverIID)) {
|
|
*aInstancePtr = (void*) ((nsIImageRequestObserver*) this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kIFrameImageLoaderIID)) {
|
|
*aInstancePtr = (void*) ((nsIFrameImageLoader*) this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*) ((nsISupports*) this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
nsresult
|
|
nsFrameImageLoader::Init(nsIPresContext* aPresContext,
|
|
nsIImageGroup* aGroup,
|
|
const nsString& aURL,
|
|
const nscolor* aBackgroundColor,
|
|
nsIFrame* aTargetFrame,
|
|
PRBool aNeedSizeUpdate)
|
|
{
|
|
NS_PRECONDITION(nsnull != aPresContext, "null ptr");
|
|
NS_PRECONDITION(nsnull == mPresContext, "double init");
|
|
|
|
if (nsnull == aPresContext) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (nsnull != mPresContext) {
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
}
|
|
mTargetFrame = aTargetFrame;
|
|
mPresContext = aPresContext;
|
|
NS_IF_ADDREF(mPresContext);
|
|
if (aNeedSizeUpdate) {
|
|
mImageLoadStatus = NS_IMAGE_LOAD_STATUS_SIZE_REQUESTED;
|
|
}
|
|
|
|
// Translate url to a C string
|
|
mURL = aURL;
|
|
char* cp = aURL.ToNewCString();
|
|
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::Init start loading for '%s', frame=%p loadStatus=%x",
|
|
cp ? cp : "(null)", mTargetFrame, mImageLoadStatus));
|
|
|
|
// Start image load request
|
|
mImageRequest = aGroup->GetImage(cp, this, aBackgroundColor, 0, 0, 0);
|
|
delete cp;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsFrameImageLoader::StopImageLoad()
|
|
{
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::StopImageLoad frame=%p loadStatus=%x",
|
|
mTargetFrame, mImageLoadStatus));
|
|
|
|
if (nsnull != mImageRequest) {
|
|
mImageRequest->RemoveObserver(this);
|
|
NS_RELEASE(mImageRequest);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsFrameImageLoader::AbortImageLoad()
|
|
{
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::AbortImageLoad frame=%p loadStatus=%x",
|
|
mTargetFrame, mImageLoadStatus));
|
|
|
|
if (nsnull != mImageRequest) {
|
|
mImageRequest->Interrupt();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsFrameImageLoader::Notify(nsIImageRequest *aImageRequest,
|
|
nsIImage *aImage,
|
|
nsImageNotification aNotificationType,
|
|
PRInt32 aParam1, PRInt32 aParam2,
|
|
void *aParam3)
|
|
{
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::Notify frame=%p type=%x p1=%x p2=%x p3=%x",
|
|
mTargetFrame, aNotificationType, aParam1, aParam2, aParam3));
|
|
|
|
nsIView* view;
|
|
nsRect damageRect;
|
|
float p2t;
|
|
const nsRect* changeRect;
|
|
|
|
switch (aNotificationType) {
|
|
case nsImageNotification_kDimensions:
|
|
mSize.width = aParam1;
|
|
mSize.height = aParam2;
|
|
mImageLoadStatus |= NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE;
|
|
if (0 != (mImageLoadStatus & NS_IMAGE_LOAD_STATUS_SIZE_REQUESTED)) {
|
|
ReflowFrame();
|
|
}
|
|
break;
|
|
|
|
case nsImageNotification_kPixmapUpdate:
|
|
if ((nsnull == mImage) && (nsnull != aImage)) {
|
|
mImage = aImage;
|
|
NS_ADDREF(aImage);
|
|
}
|
|
mImageLoadStatus |= NS_IMAGE_LOAD_STATUS_IMAGE_READY;
|
|
|
|
// Convert the rect from pixels to twips
|
|
p2t = mPresContext->GetPixelsToTwips();
|
|
changeRect = (const nsRect*)aParam3;
|
|
damageRect.x = nscoord(p2t * changeRect->x);
|
|
damageRect.y = nscoord(p2t * changeRect->y);
|
|
damageRect.width = nscoord(p2t * changeRect->width);
|
|
damageRect.height = nscoord(p2t * changeRect->height);
|
|
DamageRepairFrame(&damageRect);
|
|
break;
|
|
|
|
case nsImageNotification_kImageComplete:
|
|
// We expect to have gotten at least one pixmap update.
|
|
#if 0
|
|
// XXX Not true. Damn image library...
|
|
NS_ASSERTION((nsnull != mImage) &&
|
|
(mImageLoadStatus & NS_IMAGE_LOAD_STATUS_IMAGE_READY),
|
|
"unexpected notification order");
|
|
#else
|
|
if ((nsnull == mImage) && (nsnull != aImage)) {
|
|
mImage = aImage;
|
|
NS_ADDREF(aImage);
|
|
mImageLoadStatus |= NS_IMAGE_LOAD_STATUS_IMAGE_READY;
|
|
DamageRepairFrame(nsnull);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case nsImageNotification_kFrameComplete:
|
|
// New frame of a GIF animation
|
|
// XXX Image library sends this for all images, and not just for animated
|
|
// images. You bastards. It's a waste to re-draw the image if it's not an
|
|
// animated image, but unfortunately we don't currently have a way to tell
|
|
// whether the image is animated
|
|
DamageRepairFrame(nsnull);
|
|
break;
|
|
|
|
case nsImageNotification_kIsTransparent:
|
|
// Mark the frame's view as having transparent areas
|
|
mTargetFrame->GetView(view);
|
|
if (nsnull != view) {
|
|
view->SetContentTransparency(PR_TRUE);
|
|
view->Release();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsFrameImageLoader::NotifyError(nsIImageRequest *aImageRequest,
|
|
nsImageError aErrorType)
|
|
{
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::NotifyError frame=%p error=%x",
|
|
mTargetFrame, aErrorType));
|
|
|
|
mError = aErrorType;
|
|
mImageLoadStatus |= NS_IMAGE_LOAD_STATUS_ERROR;
|
|
if (0 != (mImageLoadStatus & NS_IMAGE_LOAD_STATUS_SIZE_REQUESTED)) {
|
|
ReflowFrame();
|
|
}
|
|
else {
|
|
DamageRepairFrame(nsnull);
|
|
}
|
|
}
|
|
|
|
static PRBool gXXXInstalledColorMap;
|
|
|
|
void
|
|
nsFrameImageLoader::DamageRepairFrame(const nsRect* aDamageRect)
|
|
{
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::DamageRepairFrame frame=%p status=%x",
|
|
mTargetFrame, mImageLoadStatus));
|
|
|
|
// XXX this should be done somewhere else, like when the window
|
|
// is created or something???
|
|
// XXX maybe there should be a seperate notification service for
|
|
// colormap events?
|
|
nsIWidget* window;
|
|
mTargetFrame->GetWindow(window);
|
|
if (!gXXXInstalledColorMap && mImage) {
|
|
nsColorMap* cmap = mImage->GetColorMap();
|
|
if ((nsnull != cmap) && (cmap->NumColors > 0)) {
|
|
window->SetColorMap(cmap);
|
|
}
|
|
gXXXInstalledColorMap = PR_TRUE;
|
|
}
|
|
NS_RELEASE(window);
|
|
|
|
// Determine damaged area and tell view manager to redraw it
|
|
nsPoint offset;
|
|
nsRect bounds;
|
|
nsIView* view;
|
|
|
|
if (nsnull == aDamageRect) {
|
|
// Invalidate the entire frame
|
|
// XXX We really only need to invalidate the clientg area of the frame...
|
|
mTargetFrame->GetRect(bounds);
|
|
bounds.x = bounds.y = 0;
|
|
}
|
|
else {
|
|
// aDamageRect represents the part of the content area that needs
|
|
// updating
|
|
bounds = *aDamageRect;
|
|
|
|
// Offset damage origin by border/padding
|
|
// XXX This is pretty sleazy. See the XXX remark below...
|
|
const nsStyleSpacing* space;
|
|
nsMargin borderPadding;
|
|
|
|
mTargetFrame->GetStyleData(eStyleStruct_Spacing, (nsStyleStruct*&)space);
|
|
space->CalcBorderPaddingFor(mTargetFrame, borderPadding);
|
|
bounds.MoveBy(borderPadding.left, borderPadding.top);
|
|
}
|
|
|
|
// XXX We should tell the frame the damage area and let it invalidate
|
|
// itself. Add some API calls to nsIFrame to allow a caller to invalidate
|
|
// parts of the frame...
|
|
mTargetFrame->GetOffsetFromView(offset, view);
|
|
nsIViewManager* vm = view->GetViewManager();
|
|
bounds.x += offset.x;
|
|
bounds.y += offset.y;
|
|
vm->UpdateView(view, bounds, 0);
|
|
NS_RELEASE(vm);
|
|
NS_RELEASE(view);
|
|
}
|
|
|
|
void
|
|
nsFrameImageLoader::ReflowFrame()
|
|
{
|
|
PR_LOG(gFrameImageLoaderLMI, PR_LOG_DEBUG,
|
|
("nsFrameImageLoader::ReflowFrame frame=%p status=%x",
|
|
mTargetFrame, mImageLoadStatus));
|
|
|
|
nsIContent* content = nsnull;
|
|
mTargetFrame->GetContent(content);
|
|
if (nsnull != content) {
|
|
nsIDocument* document = nsnull;
|
|
content->GetDocument(document);
|
|
if (nsnull != document) {
|
|
document->ContentChanged(content, nsnull);
|
|
NS_RELEASE(document);
|
|
}
|
|
NS_RELEASE(content);
|
|
}
|
|
}
|
|
|
|
NS_METHOD
|
|
nsFrameImageLoader::GetTargetFrame(nsIFrame*& aFrameResult) const
|
|
{
|
|
aFrameResult = mTargetFrame;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_METHOD
|
|
nsFrameImageLoader::GetURL(nsString& aResult) const
|
|
{
|
|
aResult = mURL;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_METHOD
|
|
nsFrameImageLoader::GetImage(nsIImage*& aResult) const
|
|
{
|
|
aResult = mImage;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_METHOD
|
|
nsFrameImageLoader::GetSize(nsSize& aResult) const
|
|
{
|
|
aResult = mSize;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_METHOD
|
|
nsFrameImageLoader::GetImageLoadStatus(PRIntn& aLoadStatus) const
|
|
{
|
|
aLoadStatus = mImageLoadStatus;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFrameImageLoader::SizeOf(nsISizeOfHandler* aHandler) const
|
|
{
|
|
aHandler->Add(sizeof(*this));
|
|
// XXX mImage
|
|
// XXX mImageRequest
|
|
return NS_OK;
|
|
}
|