merge from IMGLIB_20010126_BRANCH

This commit is contained in:
pavlov%netscape.com 2001-02-20 22:43:56 +00:00
parent eea8eb56d8
commit e3fbe3ae72
37 changed files with 1253 additions and 554 deletions

View File

@ -0,0 +1,2 @@
Makefile
.deps

View File

@ -26,7 +26,7 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk include $(DEPTH)/config/autoconf.mk
DIRS = ppm png DIRS = ppm png gif jpeg
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,2 @@
Makefile
.deps

View File

@ -0,0 +1,40 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imgjpeg
LIBRARY_NAME = imgjpeg
IS_COMPONENT = 1
CPPSRCS = nsJPEGDecoder.cpp nsJPEGFactory.cpp
EXTRA_DSO_LDOPTS = $(JPEG_LIBS) $(ZLIB_LIBS) \
$(MOZ_COMPONENT_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -28,10 +28,12 @@
#include "nspr.h" #include "nspr.h"
#include "nsUnitConverters.h"
#include "nsCRT.h" #include "nsCRT.h"
#include "nsIComponentManager.h"
#include "nsIImageContainerObserver.h"
NS_IMPL_ISUPPORTS2(nsJPEGDecoder, nsIImageDecoder, nsIOutputStream) NS_IMPL_ISUPPORTS2(nsJPEGDecoder, nsIImageDecoder, nsIOutputStream)
@ -44,14 +46,6 @@ void PR_CALLBACK il_error_exit (j_common_ptr cinfo);
/* Normal JFIF markers can't have more bytes than this. */ /* Normal JFIF markers can't have more bytes than this. */
#define MAX_JPEG_MARKER_LENGTH (((PRUint32)1 << 16) - 1) #define MAX_JPEG_MARKER_LENGTH (((PRUint32)1 << 16) - 1)
/* Possible states for JPEG source manager */
enum data_source_state {
dss_consuming_backtrack_buffer = 0, /* Must be zero for init purposes */
dss_consuming_netlib_buffer
};
/* /*
* Implementation of a JPEG src object that understands our state machine * Implementation of a JPEG src object that understands our state machine
*/ */
@ -59,26 +53,8 @@ typedef struct {
/* public fields; must be first in this struct! */ /* public fields; must be first in this struct! */
struct jpeg_source_mgr pub; struct jpeg_source_mgr pub;
nsJPEGDecoder *decoder; nsJPEGDecoder *decoder;
int bytes_to_skip; /* remaining bytes to skip */
JOCTET *netlib_buffer; /* next buffer for fill_input_buffer */
PRUint32 netlib_buflen;
enum data_source_state state;
/*
* Buffer of "remaining" characters left over after a call to
* fill_input_buffer(), when no additional data is available.
*/
JOCTET *backtrack_buffer;
size_t backtrack_buffer_size; /* Allocated size of backtrack_buffer */
size_t backtrack_buflen; /* Offset of end of active backtrack data */
size_t backtrack_num_unread_bytes; /* Length of active backtrack data */
} decoder_source_mgr; } decoder_source_mgr;
@ -88,10 +64,8 @@ nsJPEGDecoder::nsJPEGDecoder()
mState = JPEG_HEADER; mState = JPEG_HEADER;
mBuf = nsnull; mDataLen = 0;
mBufLen = 0;
mCurDataLen = 0;
mSamples = nsnull; mSamples = nsnull;
mSamples3 = nsnull; mSamples3 = nsnull;
@ -110,15 +84,22 @@ nsJPEGDecoder::~nsJPEGDecoder()
NS_IMETHODIMP nsJPEGDecoder::Init(nsIImageRequest *aRequest) NS_IMETHODIMP nsJPEGDecoder::Init(nsIImageRequest *aRequest)
{ {
mRequest = aRequest; mRequest = aRequest;
mObserver = do_QueryInterface(mRequest);
aRequest->GetImage(getter_AddRefs(mImage)); aRequest->GetImage(getter_AddRefs(mImage));
NS_NewPipe(getter_AddRefs(mInStream),
getter_AddRefs(mOutStream),
10240); // this could be a lot smaller (like 3-6k?)
/* Step 1: allocate and initialize JPEG decompression object */ /* Step 1: allocate and initialize JPEG decompression object */
/* Now we can initialize the JPEG decompression object. */ /* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&mInfo); jpeg_create_decompress(&mInfo);
/* Step 2: specify data source (eg, a file) */
decoder_source_mgr *src; decoder_source_mgr *src;
if (mInfo.src == NULL) { if (mInfo.src == NULL) {
@ -181,15 +162,12 @@ NS_IMETHODIMP nsJPEGDecoder::GetRequest(nsIImageRequest * *aRequest)
/* void close (); */ /* void close (); */
NS_IMETHODIMP nsJPEGDecoder::Close() NS_IMETHODIMP nsJPEGDecoder::Close()
{ {
// XXX this should flush the data out
// XXX progressive? ;) // XXX progressive? ;)
OutputScanlines(mInfo.output_height); // OutputScanlines(mInfo.output_height);
/* Step 7: Finish decompression */
(void) jpeg_finish_decompress(&mInfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */ /* Step 8: Release JPEG decompression object */
@ -197,15 +175,6 @@ NS_IMETHODIMP nsJPEGDecoder::Close()
/* This is an important step since it will release a good deal of memory. */ /* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&mInfo); jpeg_destroy_decompress(&mInfo);
printf("nsJPEGDecoder::Close()\n");
PR_FREEIF(mBuf);
return NS_OK; return NS_OK;
} }
@ -230,44 +199,25 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
*/ */
// XXX above what is this? // XXX above what is this?
PRUint32 readLen; if (inStr) {
mOutStream->WriteFrom(inStr, count, _retval);
if (!mBuf) { mDataLen += *_retval;
mBuf = (char*)PR_Malloc(count);
mBufLen = count;
} }
if (mBuf && count > mBufLen)
{
mBuf = (char *)PR_Realloc(mBuf, count);
mBufLen = count;
}
nsresult rv = inStr->Read(mBuf, count, &readLen);
mCurDataLen = readLen;
/* Step 2: specify data source (eg, a file) */
// i think this magically happens
// jpeg_stdio_src(&cinfo, infile);
/* Register new buffer contents with data source manager. */
/* Register new buffer contents with data source manager. */
decoder_source_mgr *src = NS_REINTERPRET_CAST(decoder_source_mgr *, mInfo.src); decoder_source_mgr *src = NS_REINTERPRET_CAST(decoder_source_mgr *, mInfo.src);
if (!mSamples && jpeg_read_header(&mInfo, TRUE) != JPEG_SUSPENDED) { int status;
switch (mState) {
case JPEG_HEADER:
/* FIXME -- Should reset dct_method and dither mode {
* for final pass of progressive JPEG /* Step 3: read file parameters with jpeg_read_header() */
*/ if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED)
mInfo.dct_method = JDCT_FASTEST; return NS_OK;
mInfo.dither_mode = JDITHER_ORDERED;
mInfo.do_fancy_upsampling = FALSE;
mInfo.enable_2pass_quant = FALSE;
mInfo.do_block_smoothing = TRUE;
/* /*
* Don't allocate a giant and superfluous memory buffer * Don't allocate a giant and superfluous memory buffer
@ -278,7 +228,15 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
/* Used to set up image size so arrays can be allocated */ /* Used to set up image size so arrays can be allocated */
jpeg_calc_output_dimensions(&mInfo); jpeg_calc_output_dimensions(&mInfo);
mImage->Init(mInfo.image_width, mInfo.image_height, nsIGFXFormat::RGB); mObserver->OnStartDecode(nsnull, nsnull);
mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
mObserver->OnStartContainer(nsnull, nsnull, mImage);
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
mFrame->Init(0, 0, mInfo.image_width, mInfo.image_height, nsIGFXFormat::RGB);
mImage->AppendFrame(mFrame);
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
/* /*
@ -302,37 +260,63 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
row_stride, 1); row_stride, 1);
} }
} else { mState = JPEG_START_DECOMPRESS;
return NS_OK;
} }
case JPEG_START_DECOMPRESS:
/* Step 4: set parameters for decompression */
/* Step 3: read file parameters with jpeg_read_header() */ /* FIXME -- Should reset dct_method and dither mode
// (void) jpeg_read_header(&mInfo, TRUE); * for final pass of progressive JPEG
/* We can ignore the return value from jpeg_read_header since */
* (a) suspension is not possible with the stdio data source, and mInfo.dct_method = JDCT_FASTEST;
* (b) we passed TRUE to reject a tables-only JPEG file as an error. mInfo.dither_mode = JDITHER_ORDERED;
* See libjpeg.doc for more info. mInfo.do_fancy_upsampling = FALSE;
*/ mInfo.enable_2pass_quant = FALSE;
mInfo.do_block_smoothing = TRUE;
/* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
/* In this example, we don't need to change any of the defaults set by /* Step 5: Start decompressor */
* jpeg_read_header(), so we do nothing here. if (jpeg_start_decompress(&mInfo) == FALSE)
*/ return NS_OK;
/* Step 5: Start decompressor */ mState = JPEG_DECOMPRESS_PROGRESSIVE;
(void) jpeg_start_decompress(&mInfo); case JPEG_DECOMPRESS_PROGRESSIVE:
/* We can ignore the return value since suspension is not possible do {
* with the stdio data source. status = jpeg_consume_input(&mInfo);
*/ } while (!((status == JPEG_SUSPENDED) ||
(status == JPEG_REACHED_EOI)));
int status; if (status == JPEG_REACHED_EOI) {
do { mState = JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT;
status = jpeg_consume_input(&mInfo); } else {
} while (!((status == JPEG_SUSPENDED) || return NS_OK;
(status == JPEG_REACHED_EOI))); }
case JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT:
jpeg_start_output(&mInfo, mInfo.input_scan_number);
OutputScanlines(-1);
jpeg_finish_output(&mInfo);
mState = JPEG_DONE;
case JPEG_DONE:
/* Step 7: Finish decompression */
if (jpeg_finish_decompress(&mInfo) == FALSE)
return NS_OK;
mState = JPEG_SINK_NON_JPEG_TRAILER;
/* we're done dude */
break;
case JPEG_SINK_NON_JPEG_TRAILER:
break;
}
/* We may need to do some setup of our own at this point before reading /* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled * the data. After jpeg_start_decompress() we have the correct scaled
@ -361,7 +345,12 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
*/ */
(void) jpeg_read_scanlines(&mInfo, buffer, 1); (void) jpeg_read_scanlines(&mInfo, buffer, 1);
/* Assume put_scanline_someplace wants a pointer and sample count. */ /* Assume put_scanline_someplace wants a pointer and sample count. */
mImage->SetBits(buffer[0], row_stride, row_stride*mInfo.output_scanline /* XXX ??? */); mFrame->SetImageData(buffer[0], row_stride, row_stride*mInfo.output_scanline /* XXX ??? */);
nsRect r(0, mInfo.output_scanline, mInfo.output_width, 1);
mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
} }
#endif #endif
@ -420,7 +409,7 @@ nsJPEGDecoder::OutputScanlines(int num_scanlines)
} }
mImage->SetBits(samples, strlen((const char *)samples), strlen((const char *)samples)*mInfo.output_scanline /* XXX ??? */); mFrame->SetImageData(samples, strlen((const char *)samples), strlen((const char *)samples)*mInfo.output_scanline /* XXX ??? */);
#if 0 #if 0
ic->imgdcb->ImgDCBHaveRow( 0, samples, 0, mInfo.output_width, mInfo.output_scanline-1, ic->imgdcb->ImgDCBHaveRow( 0, samples, 0, mInfo.output_width, mInfo.output_scanline-1,
1, ilErase, pass); 1, ilErase, pass);
@ -506,6 +495,60 @@ init_source (j_decompress_ptr jd)
{ {
} }
static NS_METHOD DiscardData(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount)
{
j_decompress_ptr jd = NS_STATIC_CAST(j_decompress_ptr, closure);
decoder_source_mgr *src = NS_REINTERPRET_CAST(decoder_source_mgr *, jd->src);
*writeCount = count;
return NS_OK;
}
void PR_CALLBACK
skip_input_data (j_decompress_ptr jd, long num_bytes)
{
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
if (num_bytes > (long)src->pub.bytes_in_buffer) {
/*
* Can't skip it all right now until we get more data from
* network stream. Set things up so that fill_input_buffer
* will skip remaining amount.
*/
PRUint32 _retval;
src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd),
src->pub.bytes_in_buffer, &_retval);
src->decoder->mDataLen -= _retval;
src->decoder->mBytesToSkip = (size_t)num_bytes - src->pub.bytes_in_buffer;
src->pub.next_input_byte += src->pub.bytes_in_buffer;
src->pub.bytes_in_buffer = 0;
} else {
/* Simple case. Just advance buffer pointer */
PRUint32 _retval;
src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd),
num_bytes, &_retval);
src->decoder->mDataLen -= _retval;
src->decoder->mBytesToSkip = 0;
src->pub.bytes_in_buffer -= (size_t)num_bytes;
src->pub.next_input_byte += num_bytes;
}
}
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* This is the callback routine from the IJG JPEG library used to supply new * This is the callback routine from the IJG JPEG library used to supply new
* data to the decompressor when its input buffer is exhausted. It juggles * data to the decompressor when its input buffer is exhausted. It juggles
@ -534,181 +577,54 @@ init_source (j_decompress_ptr jd)
* TRUE if additional data is available, FALSE if no data present and * TRUE if additional data is available, FALSE if no data present and
* the JPEG library should therefore suspend processing of input stream * the JPEG library should therefore suspend processing of input stream
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
static NS_METHOD ReadDataOut(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount)
{
j_decompress_ptr jd = NS_STATIC_CAST(j_decompress_ptr, closure);
decoder_source_mgr *src = NS_REINTERPRET_CAST(decoder_source_mgr *, jd->src);
src->pub.next_input_byte = NS_REINTERPRET_CAST(const unsigned char *, fromRawSegment);
src->pub.bytes_in_buffer = count;
*writeCount = 0; // pretend we didn't really read anything
return NS_ERROR_FAILURE; // return error so that we can point to this buffer and exit the ReadSegments loop
}
boolean PR_CALLBACK boolean PR_CALLBACK
fill_input_buffer (j_decompress_ptr jd) fill_input_buffer (j_decompress_ptr jd)
{ {
decoder_source_mgr *src = (decoder_source_mgr *)jd->src; decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
return src->decoder->FillInput(jd); PRUint32 _retval;
}
PRBool nsJPEGDecoder::FillInput(j_decompress_ptr jd) if (src->decoder->mBytesToSkip != 0) {
{ if (src->decoder->mBytesToSkip > src->decoder->mDataLen){
// read the data from the input stram... src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd),
src->decoder->mDataLen, &_retval);
decoder_source_mgr *src = (decoder_source_mgr *)jd->src; } else {
src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd),
if (mCurDataLen == 0) src->decoder->mBytesToSkip, &_retval);
return FALSE;
unsigned char *newBuffer = (unsigned char *)mBuf;
size_t newBufLen = mCurDataLen;
if (mBytesToSkip < mCurDataLen) {
newBuffer += mBytesToSkip;
newBufLen -= mBytesToSkip;
mBytesToSkip = 0;
} else {
mBytesToSkip -= newBufLen;
return FALSE; // suspend
}
src->pub.next_input_byte = newBuffer;
src->pub.bytes_in_buffer = newBufLen;
return TRUE;
#if 0
enum data_source_state src_state = src->state;
PRUint32 bytesToSkip, new_backtrack_buflen, new_buflen, roundup_buflen;
unsigned char *new_buffer;
#if 0
ILTRACE(5,("il:jpeg: fill, state=%d, nib=0x%x, bib=%d", src_state,
src->pub.next_input_byte, src->pub.bytes_in_buffer));
#endif
switch (src_state) {
/* Decompressor reached end of backtrack buffer. Return netlib buffer.*/
case dss_consuming_backtrack_buffer:
new_buffer = (unsigned char *)src->netlib_buffer;
new_buflen = src->netlib_buflen;
if ((new_buffer == NULL) || (new_buflen == 0))
goto suspend;
/*
* Clear, so that repeated calls to fill_input_buffer() do not
* deliver the same netlib buffer more than once.
*/
src->netlib_buflen = 0;
/* Discard data if asked by skip_input_data(). */
bytesToSkip = src->bytes_to_skip;
if (bytesToSkip) {
if (bytesToSkip < new_buflen) {
/* All done skipping bytes; Return what's left. */
new_buffer += bytesToSkip;
new_buflen -= bytesToSkip;
src->bytes_to_skip = 0;
} else {
/* Still need to skip some more data in the future */
src->bytes_to_skip -= (size_t)new_buflen;
goto suspend;
}
}
/* Save old backtrack buffer parameters, in case the decompressor
* backtracks and we're forced to restore its contents.
*/
src->backtrack_num_unread_bytes = src->pub.bytes_in_buffer;
src->pub.next_input_byte = new_buffer;
src->pub.bytes_in_buffer = (size_t)new_buflen;
src->state = dss_consuming_netlib_buffer;
return TRUE;
/* Reached end of netlib buffer. Suspend */
case dss_consuming_netlib_buffer:
if (src->pub.next_input_byte != src->netlib_buffer) {
/* Backtrack data has been permanently consumed. */
src->backtrack_num_unread_bytes = 0;
src->backtrack_buflen = 0;
}
/* Save remainder of netlib buffer in backtrack buffer */
new_backtrack_buflen = src->pub.bytes_in_buffer + src->backtrack_buflen;
/* Make sure backtrack buffer is big enough to hold new data. */
if (src->backtrack_buffer_size < new_backtrack_buflen) {
/* Round up to multiple of 16 bytes. */
roundup_buflen = ((new_backtrack_buflen + 15) >> 4) << 4;
if (src->backtrack_buffer_size) {
src->backtrack_buffer =
(JOCTET *)PR_REALLOC(src->backtrack_buffer, roundup_buflen);
} else {
src->backtrack_buffer = (JOCTET*)PR_MALLOC(roundup_buflen);
}
/* Check for OOM */
if (! src->backtrack_buffer) {
#if 0
j_common_ptr cinfo = (j_common_ptr)(&src->js->jd);
cinfo->err->msg_code = JERR_OUT_OF_MEMORY;
il_error_exit(cinfo);
#endif
}
src->backtrack_buffer_size = (size_t)roundup_buflen;
/* Check for malformed MARKER segment lengths. */
if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
// il_error_exit((j_common_ptr)(&src->js->jd));
}
}
/* Copy remainder of netlib buffer into backtrack buffer. */
nsCRT::memmove(src->backtrack_buffer + src->backtrack_buflen,
src->pub.next_input_byte,
src->pub.bytes_in_buffer);
/* Point to start of data to be rescanned. */
src->pub.next_input_byte = src->backtrack_buffer +
src->backtrack_buflen - src->backtrack_num_unread_bytes;
src->pub.bytes_in_buffer += src->backtrack_num_unread_bytes;
src->backtrack_buflen = (size_t)new_backtrack_buflen;
src->state = dss_consuming_backtrack_buffer;
goto suspend;
default:
PR_ASSERT(0);
return FALSE;
} }
src->decoder->mBytesToSkip -= _retval;
suspend: src->decoder->mDataLen -= _retval;
// ILTRACE(5,(" Suspending, bib=%d", src->pub.bytes_in_buffer));
return FALSE;
#endif
return FALSE;
}
void PR_CALLBACK
skip_input_data (j_decompress_ptr jd, long num_bytes)
{
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
#if 0
ILTRACE(5, ("il:jpeg: skip_input_data js->buf=0x%x js->buflen=%d skip=%d",
src->netlib_buffer, src->netlib_buflen,
num_bytes));
#endif
if (num_bytes > (long)src->pub.bytes_in_buffer) {
/*
* Can't skip it all right now until we get more data from
* network stream. Set things up so that fill_input_buffer
* will skip remaining amount.
*/
src->decoder->mBytesToSkip = (size_t)num_bytes - src->pub.bytes_in_buffer;
src->pub.next_input_byte += src->pub.bytes_in_buffer;
src->pub.bytes_in_buffer = 0;
} else {
/* Simple case. Just advance buffer pointer */
src->pub.bytes_in_buffer -= (size_t)num_bytes;
src->pub.next_input_byte += num_bytes;
} }
if (src->decoder->mDataLen != 0) {
src->decoder->mInStream->ReadSegments(ReadDataOut, NS_STATIC_CAST(void*, jd),
src->decoder->mDataLen, &_retval);
src->decoder->mDataLen -= src->pub.bytes_in_buffer;
return PR_TRUE;
} else {
return PR_FALSE;
}
} }
@ -719,5 +635,13 @@ skip_input_data (j_decompress_ptr jd, long num_bytes)
void PR_CALLBACK void PR_CALLBACK
term_source (j_decompress_ptr jd) term_source (j_decompress_ptr jd)
{ {
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
if (src->decoder->mObserver) {
src->decoder->mObserver->OnStopFrame(nsnull, nsnull, src->decoder->mFrame);
src->decoder->mObserver->OnStopContainer(nsnull, nsnull, src->decoder->mImage);
src->decoder->mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
/* No work necessary here */ /* No work necessary here */
} }

View File

@ -28,12 +28,17 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIImage2.h" #include "nsIImageContainer.h"
#include "nsIImageRequest.h" #include "nsIImageFrame.h"
#include "nsIImageDecoderObserver.h"
#include "nsIImageRequest2.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsIPipe.h"
#include "jpeglib.h" #include "jpeglib.h"
#include <setjmp.h>
#define NS_JPEGDECODER_CID \ #define NS_JPEGDECODER_CID \
{ /* 5871a422-1dd2-11b2-ab3f-e2e56be5da9c */ \ { /* 5871a422-1dd2-11b2-ab3f-e2e56be5da9c */ \
0x5871a422, \ 0x5871a422, \
@ -77,18 +82,21 @@ public:
protected: protected:
int OutputScanlines(int num_scanlines); int OutputScanlines(int num_scanlines);
private: public:
nsCOMPtr<nsIImage2> mImage; nsCOMPtr<nsIImageContainer> mImage;
nsCOMPtr<nsIImageFrame> mFrame;
nsCOMPtr<nsIImageRequest> mRequest; nsCOMPtr<nsIImageRequest> mRequest;
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsIImageDecoderObserver> mObserver;
struct jpeg_decompress_struct mInfo; struct jpeg_decompress_struct mInfo;
decoder_error_mgr mErr; decoder_error_mgr mErr;
jstate mState; jstate mState;
char *mBuf; nsCOMPtr<nsIInputStream> mInStream;
PRUint32 mBufLen; nsCOMPtr<nsIOutputStream> mOutStream;
PRUint32 mCurDataLen;
PRUint32 mDataLen;
JSAMPARRAY mSamples; JSAMPARRAY mSamples;
JSAMPARRAY mSamples3; JSAMPARRAY mSamples3;

View File

@ -34,7 +34,7 @@ static nsModuleComponentInfo components[] =
{ {
{ "ppm decoder", { "ppm decoder",
NS_JPEGDECODER_CID, NS_JPEGDECODER_CID,
"@mozilla.org/image/decoder?image/jpeg;1", "@mozilla.org/image/decoder;2?type=image/jpeg",
nsJPEGDecoderConstructor, }, nsJPEGDecoderConstructor, },
}; };

View File

@ -21,6 +21,6 @@
DEPTH=..\..\.. DEPTH=..\..\..
DIRS = ppm png DIRS = ppm gif png jpeg
!include $(DEPTH)\config\rules.mak !include $(DEPTH)\config\rules.mak

View File

@ -39,6 +39,7 @@ LLIBS=\
$(DIST)\lib\xpcom.lib \ $(DIST)\lib\xpcom.lib \
$(DIST)\lib\png.lib \ $(DIST)\lib\png.lib \
$(DIST)\lib\zlib.lib \ $(DIST)\lib\zlib.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL) $(NULL)
include <$(DEPTH)\config\rules.mak> include <$(DEPTH)\config\rules.mak>

View File

@ -34,6 +34,11 @@
#include "nsIStreamObserver.h" #include "nsIStreamObserver.h"
#include "nsRect.h"
#include "nsMemory.h"
#include "nsIImageContainerObserver.h"
// XXX we need to be sure to fire onStopDecode messages to mObserver in error cases. // XXX we need to be sure to fire onStopDecode messages to mObserver in error cases.
@ -47,11 +52,19 @@ nsPNGDecoder::nsPNGDecoder()
mPNG = nsnull; mPNG = nsnull;
mInfo = nsnull; mInfo = nsnull;
colorLine = 0;
alphaLine = 0;
interlacebuf = 0;
} }
nsPNGDecoder::~nsPNGDecoder() nsPNGDecoder::~nsPNGDecoder()
{ {
if (colorLine)
nsMemory::Free(colorLine);
if (alphaLine)
nsMemory::Free(alphaLine);
if (interlacebuf)
nsMemory::Free(interlacebuf);
} }
@ -85,7 +98,7 @@ NS_IMETHODIMP nsPNGDecoder::Init(nsIImageRequest *aRequest)
} }
/* use ic as libpng "progressive pointer" (retrieve in callbacks) */ /* use ic as libpng "progressive pointer" (retrieve in callbacks) */
png_set_progressive_read_fn(mPNG, this, nsPNGDecoder::info_callback, nsPNGDecoder::row_callback, nsPNGDecoder::end_callback); png_set_progressive_read_fn(mPNG, NS_STATIC_CAST(png_voidp, this), nsPNGDecoder::info_callback, nsPNGDecoder::row_callback, nsPNGDecoder::end_callback);
return NS_OK; return NS_OK;
} }
@ -136,6 +149,17 @@ static NS_METHOD ReadDataOut(nsIInputStream* in,
PRUint32 *writeCount) PRUint32 *writeCount)
{ {
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, closure); nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, closure);
// we need to do the setjmp here otherwise bad things will happen
if (setjmp(decoder->mPNG->jmpbuf)) {
png_destroy_read_struct(&decoder->mPNG, &decoder->mInfo, NULL);
// is this NS_ERROR_FAILURE enough?
decoder->mRequest->Cancel(NS_BINDING_ABORTED); // XXX is this the correct error ?
return NS_ERROR_FAILURE;
}
*writeCount = decoder->ProcessData((unsigned char*)fromRawSegment, count); *writeCount = decoder->ProcessData((unsigned char*)fromRawSegment, count);
return NS_OK; return NS_OK;
} }
@ -150,16 +174,7 @@ PRUint32 nsPNGDecoder::ProcessData(unsigned char *data, PRUint32 count)
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */ /* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{ {
PRUint32 sourceOffset = *_retval; // PRUint32 sourceOffset = *_retval;
if (setjmp(mPNG->jmpbuf)) {
png_destroy_read_struct(&mPNG, &mInfo, NULL);
// is this NS_ERROR_FAILURE enough?
mRequest->Cancel(NS_BINDING_ABORTED); // XXX is this the correct error ?
return NS_ERROR_FAILURE;
}
inStr->ReadSegments(ReadDataOut, this, count, _retval); inStr->ReadSegments(ReadDataOut, this, count, _retval);
@ -313,13 +328,13 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr)); nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
if (decoder->mObserver) if (decoder->mObserver)
decoder->mObserver->OnStartDecode(nsnull); decoder->mObserver->OnStartDecode(nsnull, nsnull);
// since the png is only 1 frame, initalize the container to the width and height of the frame // since the png is only 1 frame, initalize the container to the width and height of the frame
decoder->mImage->Init(width, height); decoder->mImage->Init(width, height, decoder->mObserver);
if (decoder->mObserver) if (decoder->mObserver)
decoder->mObserver->OnStartContainer(nsnull, decoder->mImage); decoder->mObserver->OnStartContainer(nsnull, nsnull, decoder->mImage);
decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2"); decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
#if 0 #if 0
@ -328,21 +343,44 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
#endif #endif
gfx_format format;
if (channels == 3) {
format = nsIGFXFormat::RGB;
} else if (channels > 3) {
if (alpha_bits == 8) {
decoder->mImage->GetPreferredAlphaChannelFormat(&format);
} else if (alpha_bits == 1) {
format = nsIGFXFormat::RGB_A1;
}
}
#ifdef XP_PC
// XXX this works...
format += 1; // RGB to BGR
#endif
// then initalize the frame and append it to the container
decoder->mFrame->Init(0, 0, width, height, format);
decoder->mImage->AppendFrame(decoder->mFrame); decoder->mImage->AppendFrame(decoder->mFrame);
if (decoder->mObserver) if (decoder->mObserver)
decoder->mObserver->OnStartFrame(nsnull, decoder->mFrame); decoder->mObserver->OnStartFrame(nsnull, nsnull, decoder->mFrame);
PRUint32 bpr, abpr;
decoder->mFrame->GetImageBytesPerRow(&bpr);
decoder->mFrame->GetAlphaBytesPerRow(&abpr);
decoder->colorLine = (PRUint8 *)nsMemory::Alloc(bpr);
if (channels > 3)
decoder->alphaLine = (PRUint8 *)nsMemory::Alloc(abpr);
// then initalize the frame (which was appended above in nsPNGDecoder::Init()) if (interlace_type == PNG_INTERLACE_ADAM7) {
if (channels == 3) { decoder->interlacebuf = (PRUint8 *)nsMemory::Alloc(channels*width*height);
decoder->mFrame->Init(0, 0, width, height, nsIGFXFormat::RGB); decoder->ibpr = channels*width;
} else if (channels > 3) { if (!decoder->interlacebuf) {
if (alpha_bits == 8) { // return NS_ERROR_FAILURE;
decoder->mFrame->Init(0, 0, width, height, nsIGFXFormat::RGBA); }
} else if (alpha_bits == 1) {
decoder->mFrame->Init(0, 0, width, height, nsIGFXFormat::RGB_A1);
}
} }
return; return;
@ -385,23 +423,77 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
*/ */
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr)); nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
PRUint32 bpr; PRUint32 bpr, abpr;
decoder->mFrame->GetBytesPerRow(&bpr); decoder->mFrame->GetImageBytesPerRow(&bpr);
decoder->mFrame->GetAlphaBytesPerRow(&abpr);
PRUint32 length; PRUint32 length;
PRUint8 *bits; PRUint8 *bits;
decoder->mFrame->GetBits(&bits, &length); decoder->mFrame->GetImageData(&bits, &length);
png_bytep line; png_bytep line;
if (bits) { if (decoder->interlacebuf) {
line = bits+(row_num*bpr); line = decoder->interlacebuf+(row_num*decoder->ibpr);
png_progressive_combine_row(png_ptr, line, new_row); png_progressive_combine_row(png_ptr, line, new_row);
} }
else else
line = new_row; line = new_row;
if (new_row) { if (new_row) {
decoder->mFrame->SetBits((PRUint8*)line, bpr, row_num*bpr); nscoord width;
decoder->mFrame->GetWidth(&width);
PRUint32 iwidth = width;
gfx_format format;
decoder->mFrame->GetFormat(&format);
PRUint8 *aptr, *cptr;
switch (format) {
case nsIGFXFormat::RGB:
case nsIGFXFormat::BGR:
decoder->mFrame->SetImageData((PRUint8*)line, bpr, row_num*bpr);
break;
case nsIGFXFormat::RGB_A1:
case nsIGFXFormat::BGR_A1:
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
memset(aptr, 0, abpr);
for (PRUint32 x=0; x<iwidth; x++) {
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
if (*line++) {
aptr[x>>3] |= 1<<(7-x&0x7);
}
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
}
break;
case nsIGFXFormat::RGB_A8:
case nsIGFXFormat::BGR_A8:
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
for (PRUint32 x=0; x<iwidth; x++) {
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
*aptr++ = *line++;
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
}
break;
case nsIGFXFormat::RGBA:
case nsIGFXFormat::BGRA:
decoder->mFrame->SetImageData(line, bpr, row_num*bpr);
break;
}
nsRect r(0, row_num, width, 1);
decoder->mObserver->OnDataAvailable(nsnull, nsnull, decoder->mFrame, &r);
} }
} }
@ -425,9 +517,9 @@ nsPNGDecoder::end_callback(png_structp png_ptr, png_infop info_ptr)
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr)); nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
if (decoder->mObserver) { if (decoder->mObserver) {
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame); decoder->mObserver->OnStopFrame(nsnull, nsnull, decoder->mFrame);
decoder->mObserver->OnStopContainer(nsnull, decoder->mImage); decoder->mObserver->OnStopContainer(nsnull, nsnull, decoder->mImage);
decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull); decoder->mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
} }
} }

View File

@ -29,7 +29,7 @@
#include "nsIImageContainer.h" #include "nsIImageContainer.h"
#include "nsIImageDecoderObserver.h" #include "nsIImageDecoderObserver.h"
#include "nsIImageFrame.h" #include "nsIImageFrame.h"
#include "nsIImageRequest.h" #include "nsIImageRequest2.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -66,7 +66,7 @@ end_callback(png_structp png_ptr, png_infop info_ptr);
inline PRUint32 ProcessData(unsigned char *data, PRUint32 count); inline PRUint32 ProcessData(unsigned char *data, PRUint32 count);
private: public:
nsCOMPtr<nsIImageContainer> mImage; nsCOMPtr<nsIImageContainer> mImage;
nsCOMPtr<nsIImageFrame> mFrame; nsCOMPtr<nsIImageFrame> mFrame;
nsCOMPtr<nsIImageRequest> mRequest; nsCOMPtr<nsIImageRequest> mRequest;
@ -74,6 +74,9 @@ private:
png_structp mPNG; png_structp mPNG;
png_infop mInfo; png_infop mInfo;
PRUint8 *colorLine, *alphaLine;
PRUint8 *interlacebuf;
PRUint32 ibpr;
}; };
#endif // nsPNGDecoder_h__ #endif // nsPNGDecoder_h__

View File

@ -34,7 +34,11 @@ static nsModuleComponentInfo components[] =
{ {
{ "PNG decoder", { "PNG decoder",
NS_PNGDECODER_CID, NS_PNGDECODER_CID,
"@mozilla.org/image/decoder?image/png;1", "@mozilla.org/image/decoder;2?type=image/png",
nsPNGDecoderConstructor, },
{ "PNG decoder",
NS_PNGDECODER_CID,
"@mozilla.org/image/decoder;2?type=image/x-png",
nsPNGDecoderConstructor, }, nsPNGDecoderConstructor, },
}; };

View File

@ -37,6 +37,7 @@ OBJS = \
LLIBS=\ LLIBS=\
$(LIBNSPR) \ $(LIBNSPR) \
$(DIST)\lib\xpcom.lib \ $(DIST)\lib\xpcom.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL) $(NULL)
include <$(DEPTH)\config\rules.mak> include <$(DEPTH)\config\rules.mak>

View File

@ -20,23 +20,20 @@
* Contributor(s): * Contributor(s):
* Stuart Parmenter <pavlov@netscape.com> * Stuart Parmenter <pavlov@netscape.com>
* *
*
* the ppm decoding function is from Tim Rowley <tor@cs.brown.edu>
* i dunno its license
*
*/ */
#include "nsPPMDecoder.h" #include "nsPPMDecoder.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsIImageContainer.h" #include "nsIImageContainer.h"
#include "nsIImageContainerObserver.h"
#include "nspr.h" #include "nspr.h"
#include "nsUnitConverters.h"
#include "nsIComponentManager.h" #include "nsIComponentManager.h"
#include "nsRect.h"
NS_IMPL_ISUPPORTS2(nsPPMDecoder, nsIImageDecoder, nsIOutputStream) NS_IMPL_ISUPPORTS2(nsPPMDecoder, nsIImageDecoder, nsIOutputStream)
@ -63,15 +60,14 @@ NS_IMETHODIMP nsPPMDecoder::Init(nsIImageRequest *aRequest)
{ {
mRequest = aRequest; mRequest = aRequest;
nsCOMPtr<nsIImageContainer> container; mObserver = do_QueryInterface(aRequest); // we're holding 2 strong refs to the request.
aRequest->GetImage(getter_AddRefs(container));
mImage = do_CreateInstance("@mozilla.org/gfx/image/frame;2"); aRequest->GetImage(getter_AddRefs(mImage));
if (!mImage)
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!mFrame)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
container->AppendFrame(mImage);
return NS_OK; return NS_OK;
} }
@ -93,11 +89,11 @@ NS_IMETHODIMP nsPPMDecoder::GetRequest(nsIImageRequest * *aRequest)
/* void close (); */ /* void close (); */
NS_IMETHODIMP nsPPMDecoder::Close() NS_IMETHODIMP nsPPMDecoder::Close()
{ {
printf("nsPPMDecoder::Close()\n"); if (mObserver) {
mObserver->OnStopFrame(nsnull, nsnull, mFrame);
// XXX hack mObserver->OnStopContainer(nsnull, nsnull, mImage);
gfx_format format; mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
mImage->GetFormat(&format); }
return NS_OK; return NS_OK;
} }
@ -185,6 +181,8 @@ NS_IMETHODIMP nsPPMDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRU
if (mDataReceived == 0) { if (mDataReceived == 0) {
mObserver->OnStartDecode(nsnull, nsnull);
// Check the magic number // Check the magic number
char type; char type;
if ((sscanf(data, "P%c\n", &type) !=1) || (type != '6')) { if ((sscanf(data, "P%c\n", &type) !=1) || (type != '6')) {
@ -217,17 +215,23 @@ NS_IMETHODIMP nsPPMDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRU
readLen -= i + j; readLen -= i + j;
dataLen = readLen; // since this is the first pass, we don't have any data waiting that we need to keep track of dataLen = readLen; // since this is the first pass, we don't have any data waiting that we need to keep track of
// XXX this isn't the width/height that was actually requested.. get that from mRequest. mImage->Init(w, h, mObserver);
mImage->Init(0, 0, w, h, nsIGFXFormat::RGB); if (mObserver)
mObserver->OnStartContainer(nsnull, nsnull, mImage);
mFrame->Init(0, 0, w, h, nsIGFXFormat::RGB);
mImage->AppendFrame(mFrame);
if (mObserver)
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
} }
PRUint32 bpr; PRUint32 bpr;
gfx_dimension width; nscoord width;
mImage->GetBytesPerRow(&bpr); mFrame->GetImageBytesPerRow(&bpr);
mImage->GetWidth(&width); mFrame->GetWidth(&width);
PRUint32 real_bpr = GFXCoordToIntCeil(width) * 3; // XXX ceil?
PRUint32 real_bpr = width * 3;
PRUint32 i = 0; PRUint32 i = 0;
PRUint32 rownum = mDataWritten / real_bpr; // XXX this better not have a decimal PRUint32 rownum = mDataWritten / real_bpr; // XXX this better not have a decimal
@ -238,7 +242,12 @@ NS_IMETHODIMP nsPPMDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRU
do { do {
PRUint8 *line = (PRUint8*)data + i*real_bpr; PRUint8 *line = (PRUint8*)data + i*real_bpr;
mImage->SetBits(line, real_bpr, (rownum++)*bpr); mFrame->SetImageData(line, real_bpr, (rownum++)*bpr);
nsRect r(0, rownum, width, 1);
mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
wroteLen += real_bpr ; wroteLen += real_bpr ;
i++; i++;
} while(dataLen >= real_bpr * (i+1)); } while(dataLen >= real_bpr * (i+1));

View File

@ -28,8 +28,10 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIImageContainer.h"
#include "nsIImageDecoderObserver.h"
#include "nsIImageFrame.h" #include "nsIImageFrame.h"
#include "nsIImageRequest.h" #include "nsIImageRequest2.h"
#define NS_PPMDECODER_CID \ #define NS_PPMDECODER_CID \
{ /* e90bfa06-1dd1-11b2-8217-f38fe5d431a2 */ \ { /* e90bfa06-1dd1-11b2-8217-f38fe5d431a2 */ \
@ -50,8 +52,11 @@ public:
virtual ~nsPPMDecoder(); virtual ~nsPPMDecoder();
private: private:
nsCOMPtr<nsIImageFrame> mImage; nsCOMPtr<nsIImageContainer> mImage;
nsCOMPtr<nsIImageFrame> mFrame;
nsCOMPtr<nsIImageRequest> mRequest; nsCOMPtr<nsIImageRequest> mRequest;
nsCOMPtr<nsIImageDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
PRUint32 mDataReceived; PRUint32 mDataReceived;
PRUint32 mDataWritten; PRUint32 mDataWritten;

View File

@ -34,7 +34,7 @@ static nsModuleComponentInfo components[] =
{ {
{ "ppm decoder", { "ppm decoder",
NS_PPMDECODER_CID, NS_PPMDECODER_CID,
"@mozilla.org/image/decoder?image/x-portable-pixmap;1", "@mozilla.org/image/decoder;2?type=image/x-portable-pixmap",
nsPPMDecoderConstructor, }, nsPPMDecoderConstructor, },
}; };

Binary file not shown.

View File

@ -0,0 +1,3 @@
Makefile
.deps
_xpidlgen

View File

@ -0,0 +1,4 @@
nsIImageDecoder.idl
nsIImageDecoderObserver.idl
nsIImageLoader.idl
nsIImageRequest2.idl

View File

@ -31,7 +31,7 @@ MODULE = imglib2
XPIDLSRCS = nsIImageDecoder.idl \ XPIDLSRCS = nsIImageDecoder.idl \
nsIImageDecoderObserver.idl \ nsIImageDecoderObserver.idl \
nsIImageLoader.idl \ nsIImageLoader.idl \
nsIImageRequest.idl nsIImageRequest2.idl
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -31,7 +31,7 @@ XPIDLSRCS = \
.\nsIImageDecoder.idl \ .\nsIImageDecoder.idl \
.\nsIImageDecoderObserver.idl \ .\nsIImageDecoderObserver.idl \
.\nsIImageLoader.idl \ .\nsIImageLoader.idl \
.\nsIImageRequest.idl \ .\nsIImageRequest2.idl \
$(NULL) $(NULL)

View File

@ -27,9 +27,25 @@
interface nsIImageRequest; interface nsIImageRequest;
/**
* nsIImageDecoder interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(9eebf43a-1dd1-11b2-953e-f1782f4cbad3)] [scriptable, uuid(9eebf43a-1dd1-11b2-953e-f1782f4cbad3)]
interface nsIImageDecoder : nsIOutputStream interface nsIImageDecoder : nsIOutputStream
{ {
/**
* Initalize an image decoder.
* @param aRequest the request that owns the decoder.
*
* @note The decode should QI \a aRequest to an nsIImageDecoderObserver
* and should send decoder notifications to the request.
* The decoder should always pass NULL as the first two parameters to
* all of the nsIImageDecoderObserver APIs.
*/
void init(in nsIImageRequest aRequest); void init(in nsIImageRequest aRequest);
/// allows access to the nsIImage we have to put bits in to. /// allows access to the nsIImage we have to put bits in to.

View File

@ -21,13 +21,17 @@
* Stuart Parmenter <pavlov@netscape.com> * Stuart Parmenter <pavlov@netscape.com>
*/ */
#include "nsISupports.idl" #include "nsIImageContainerObserver.idl"
#include "gfxtypes.idl" #include "gfxtypes.idl"
interface nsIImageRequest; interface nsIImageRequest;
interface nsIImageContainer; interface nsIImageContainer;
interface nsIImageFrame; interface nsIImageFrame;
%{C++
#include "nsRect.h"
%}
/** /**
* nsIImageDecoderObserver interface * nsIImageDecoderObserver interface
* *
@ -36,42 +40,42 @@ interface nsIImageFrame;
* @see imagelib2 * @see imagelib2
*/ */
[scriptable, uuid(350163d2-1dd2-11b2-9e69-89959ecec1f3)] [scriptable, uuid(350163d2-1dd2-11b2-9e69-89959ecec1f3)]
interface nsIImageDecoderObserver : nsISupports interface nsIImageDecoderObserver : nsIImageContainerObserver
{ {
/** /**
* called as soon as the image begins getting decoded * called as soon as the image begins getting decoded
*/ */
void onStartDecode(in nsIImageRequest request); void onStartDecode(in nsIImageRequest request, in nsISupports cx);
/** /**
* called once the image has been inited and therefore has a width and height * called once the image has been inited and therefore has a width and height
*/ */
void onStartContainer(in nsIImageRequest request, in nsIImageContainer image); void onStartContainer(in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image);
/** /**
* called when each frame is created * called when each frame is created
*/ */
void onStartFrame(in nsIImageRequest request, in nsIImageFrame frame); void onStartFrame(in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame);
/** /**
* called when some part of the frame has new data in it * called when some part of the frame has new data in it
*/ */
[noscript] void onDataAvailable(in nsIImageRequest request, in nsIImageFrame frame, [const] in nsRect2 rect); [noscript] void onDataAvailable(in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame, [const] in nsRect rect);
/** /**
* called when a frame is finished decoding * called when a frame is finished decoding
*/ */
void onStopFrame(in nsIImageRequest request, in nsIImageFrame frame); void onStopFrame(in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame);
/** /**
* probably not needed. called right before onStopDecode * probably not needed. called right before onStopDecode
*/ */
void onStopContainer(in nsIImageRequest request, in nsIImageContainer image); void onStopContainer(in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image);
/** /**
* called when the decoder is dying off * called when the decoder is dying off
*/ */
void onStopDecode(in nsIImageRequest request, in nsresult status, void onStopDecode(in nsIImageRequest request, in nsISupports cx,
in wstring statusArg); in nsresult status, in wstring statusArg);
}; };

View File

@ -24,19 +24,42 @@
#include "nsISupports.idl" #include "nsISupports.idl"
#include "gfxtypes.idl" #include "gfxtypes.idl"
interface nsIImage; interface nsIImageDecoderObserver;
interface nsIImageRequest; interface nsIImageRequest;
interface nsISimpleEnumerator; interface nsISimpleEnumerator;
interface nsIStreamListener;
interface nsIURI; interface nsIURI;
interface nsIChannel;
/**
* nsIImageLoader interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(4c8cf1e0-1dd2-11b2-aff9-c51cdbfcb6da)] [scriptable, uuid(4c8cf1e0-1dd2-11b2-aff9-c51cdbfcb6da)]
interface nsIImageLoader : nsISupports interface nsIImageLoader : nsISupports
{ {
nsIImageRequest loadImage(in nsIURI uri); /**
* Start the load and decode of an image.
* @param uri the URI to load
* @param aObserver the observer
* @param cx some random data
*/
nsIImageRequest loadImage(in nsIURI uri, in nsIImageDecoderObserver aObserver, in nsISupports cx);
/**
* Start the load and decode of an image.
* @param uri the URI to load
* @param aObserver the observer
* @param cx some random data
*/
nsIImageRequest loadImageWithChannel(in nsIChannel aChannel, in nsIImageDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener aListener);
/** /**
* Returns the channels contained directly in this group. * Returns the channels contained directly in this group.
* Enumerator element type: nsIImageRequest. * @note Enumerator element type: nsIImageRequest.
*/ */
readonly attribute nsISimpleEnumerator requests; readonly attribute nsISimpleEnumerator requests;
}; };

View File

@ -22,23 +22,42 @@
*/ */
#include "nsISupports.idl" #include "nsISupports.idl"
#include "nsIRequest.idl"
#include "gfxtypes.idl"
interface nsIChannel;
interface nsIImageContainer; interface nsIImageContainer;
/**
* nsIImageRequest interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(ccf705f6-1dd1-11b2-82ef-e18eccf7f7ec)] [scriptable, uuid(ccf705f6-1dd1-11b2-82ef-e18eccf7f7ec)]
interface nsIImageRequest : nsIRequest interface nsIImageRequest : nsISupports
{ {
// const values for GetStatus() to be used someday... void cancel(in nsresult status);
// const long STATUS_NONE = 0x0;
// const long STATUS_SIZE_AVAILABLE = 0x1;
// const long STATUS_IMAGE_READY = 0x2;
// const long STATUS_ERROR = 0x4;
void init(in nsIChannel aChannel); /**
* the image container...
/// @return the image object associated with the request. * @return the image object associated with the request.
* @attention NEED DOCS
*/
readonly attribute nsIImageContainer image; readonly attribute nsIImageContainer image;
/**
* Bits set in the return value from imageStatus
* @name statusflags
*/
//@{
const long STATUS_NONE = 0x0;
const long STATUS_SIZE_AVAILABLE = 0x1;
const long STATUS_LOAD_COMPLETE = 0x2;
const long STATUS_ERROR = 0x4;
//@}
/**
* something
* @attention NEED DOCS
*/
readonly attribute unsigned long imageStatus;
}; };

View File

@ -0,0 +1,2 @@
Makefile
.deps

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "ImageCache.h"
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
class nsIURIKey : public nsHashKey {
protected:
nsCOMPtr<nsIURI> mKey;
public:
nsIURIKey(nsIURI* key) : mKey(key) {}
~nsIURIKey(void) {}
PRUint32 HashCode(void) const {
nsXPIDLCString spec;
mKey->GetSpec(getter_Copies(spec));
return (PRUint32) PL_HashString(spec);
}
PRBool Equals(const nsHashKey *aKey) const {
PRBool eq;
mKey->Equals( ((nsIURIKey*) aKey)->mKey, &eq );
return eq;
}
nsHashKey *Clone(void) const {
return new nsIURIKey(mKey);
}
};
ImageCache::ImageCache()
{
/* member initializers and constructor code */
}
nsSupportsHashtable mCache;
ImageCache::~ImageCache()
{
/* destructor code */
}
PRBool ImageCache::Put(nsIURI *aKey, nsImageRequest *request)
{
nsIURIKey key(aKey);
return mCache.Put(&key, NS_STATIC_CAST(nsIImageRequest*, request));
}
PRBool ImageCache::Get(nsIURI *aKey, nsImageRequest **request)
{
nsIURIKey key(aKey);
nsImageRequest *sup = NS_REINTERPRET_CAST(nsImageRequest*, NS_STATIC_CAST(nsIImageRequest*, mCache.Get(&key))); // this addrefs
if (sup) {
*request = sup;
return PR_TRUE;
} else {
return PR_FALSE;
}
}
PRBool ImageCache::Remove(nsIURI *aKey)
{
nsIURIKey key(aKey);
return mCache.Remove(&key);
}

View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef ImageCache_h__
#define ImageCache_h__
#include "nsIURI.h"
#include "nsImageRequest.h"
#define IMAGE_CACHE_CID \
{ /* 70058a20-1dd2-11b2-9d22-db0a9d82e8bd */ \
0x70058a20, \
0x1dd2, \
0x11b2, \
{0x9d, 0x22, 0xdb, 0x0a, 0x9d, 0x82, 0xe8, 0xbd} \
}
class ImageCache
{
public:
ImageCache();
~ImageCache();
/* additional members */
static PRBool Put(nsIURI *aKey, nsImageRequest *request);
static PRBool Get(nsIURI *aKey, nsImageRequest **request);
static PRBool Remove(nsIURI *aKey);
private:
};
#endif

View File

@ -30,9 +30,11 @@ MODULE = imglib2
LIBRARY_NAME = imglib2 LIBRARY_NAME = imglib2
IS_COMPONENT = 1 IS_COMPONENT = 1
CPPSRCS = nsImageFactory.cpp \ CPPSRCS = ImageCache.cpp \
nsImageLoader.cpp \ nsImageFactory.cpp \
nsImageRequest.cpp nsImageLoader.cpp \
nsImageRequest.cpp \
nsImageRequestProxy.cpp
EXTRA_DSO_LDOPTS = \ EXTRA_DSO_LDOPTS = \
$(MOZ_COMPONENT_LIBS) \ $(MOZ_COMPONENT_LIBS) \

View File

@ -30,8 +30,10 @@ DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL MAKE_OBJ_TYPE = DLL
OBJS = \ OBJS = \
.\$(OBJDIR)\ImageCache.obj \
.\$(OBJDIR)\nsImageLoader.obj \ .\$(OBJDIR)\nsImageLoader.obj \
.\$(OBJDIR)\nsImageRequest.obj \ .\$(OBJDIR)\nsImageRequest.obj \
.\$(OBJDIR)\nsImageRequestProxy.obj \
.\$(OBJDIR)\nsImageFactory.obj \ .\$(OBJDIR)\nsImageFactory.obj \
$(NULL) $(NULL)

View File

@ -26,11 +26,13 @@
#include "nsImageLoader.h" #include "nsImageLoader.h"
#include "nsImageRequest.h" #include "nsImageRequest.h"
#include "nsImageRequestProxy.h"
// objects that just require generic constructors // objects that just require generic constructors
NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageLoader) NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageLoader)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageRequest) NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageRequestProxy)
static nsModuleComponentInfo components[] = static nsModuleComponentInfo components[] =
{ {
@ -40,9 +42,12 @@ static nsModuleComponentInfo components[] =
nsImageLoaderConstructor, }, nsImageLoaderConstructor, },
{ "image request", { "image request",
NS_IMAGEREQUEST_CID, NS_IMAGEREQUEST_CID,
"@mozilla.org/image/request;1", "@mozilla.org/image/request/real;1",
nsImageRequestConstructor, }, nsImageRequestConstructor, },
{ "image request proxy",
NS_IMAGEREQUESTPROXY_CID,
"@mozilla.org/image/request/proxy;1",
nsImageRequestProxyConstructor, },
}; };
NS_IMPL_NSGETMODULE("nsImageLib2Module", components) NS_IMPL_NSGETMODULE("nsImageLib2Module", components)

View File

@ -23,7 +23,7 @@
#include "nsImageLoader.h" #include "nsImageLoader.h"
#include "nsIImageRequest.h" #include "nsIImageRequest2.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
@ -33,57 +33,136 @@
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsImageRequest.h"
#include "nsImageRequestProxy.h"
#include "ImageCache.h"
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"
#ifdef LOADER_THREADSAFE
#include "nsAutoLock.h"
#endif
static NS_DEFINE_CID(kImageRequestCID, NS_IMAGEREQUEST_CID);
static NS_DEFINE_CID(kImageRequestProxyCID, NS_IMAGEREQUESTPROXY_CID);
#ifdef LOADER_THREADSAFE
NS_IMPL_THREADSAFE_ISUPPORTS1(nsImageLoader, nsIImageLoader)
#else
NS_IMPL_ISUPPORTS1(nsImageLoader, nsIImageLoader) NS_IMPL_ISUPPORTS1(nsImageLoader, nsIImageLoader)
#endif
nsImageLoader::nsImageLoader() nsImageLoader::nsImageLoader()
{ {
NS_INIT_ISUPPORTS(); NS_INIT_ISUPPORTS();
/* member initializers and constructor code */ /* member initializers and constructor code */
#ifdef LOADER_THREADSAFE
mLock = PR_NewLock();
#endif
} }
nsImageLoader::~nsImageLoader() nsImageLoader::~nsImageLoader()
{ {
/* destructor code */ /* destructor code */
#ifdef LOADER_THREADSAFE
PR_DestroyLock(mLock);
#endif
} }
//#define IMAGE_THREADPOOL 1 /* nsIImageRequest loadImage (in nsIURI uri, in nsIImageDecoderObserver aObserver, in nsISupports cx); */
NS_IMETHODIMP nsImageLoader::LoadImage(nsIURI *aURI, nsIImageDecoderObserver *aObserver, nsISupports *cx, nsIImageRequest **_retval)
/* nsIImageRequest loadImage (in nsIURI uri, in gfx_dimension width, in gfx_dimension height); */
NS_IMETHODIMP nsImageLoader::LoadImage(nsIURI *aURI, nsIImageRequest **_retval)
{ {
NS_ASSERTION(aURI, "nsImageLoader::LoadImage -- NULL URI pointer");
#ifdef IMAGE_THREADPOOL nsImageRequest *imgRequest = nsnull;
if (!mThreadPool) {
NS_NewThreadPool(getter_AddRefs(mThreadPool), ImageCache::Get(aURI, &imgRequest); // addrefs
1, 4, if (!imgRequest) {
512, #ifdef LOADER_THREADSAFE
PR_PRIORITY_NORMAL, nsAutoLock lock(mLock); // lock when we are adding things to the cache
PR_GLOBAL_THREAD); #endif
nsCOMPtr<nsIIOService> ioserv(do_GetService("@mozilla.org/network/io-service;1"));
if (!ioserv) return NS_ERROR_FAILURE;
nsCOMPtr<nsIChannel> newChannel;
ioserv->NewChannelFromURI(aURI, getter_AddRefs(newChannel));
if (!newChannel) return NS_ERROR_FAILURE;
// XXX do we need to SetOwner here?
newChannel->SetOwner(this); // the channel is now holding a strong ref to 'this'
nsCOMPtr<nsIImageRequest> req(do_CreateInstance(kImageRequestCID));
imgRequest = NS_REINTERPRET_CAST(nsImageRequest*, req.get());
NS_ADDREF(imgRequest);
imgRequest->Init(newChannel);
ImageCache::Put(aURI, imgRequest);
newChannel->AsyncRead(NS_STATIC_CAST(nsIStreamListener *, imgRequest), cx); // XXX are we calling this too early?
} }
nsCOMPtr<nsIImageRequest> proxyRequest(do_CreateInstance(kImageRequestProxyCID));
// init adds itself to imgRequest's list of observers
NS_REINTERPRET_CAST(nsImageRequestProxy*, proxyRequest.get())->Init(imgRequest, aObserver, cx);
NS_RELEASE(imgRequest);
*_retval = proxyRequest;
NS_ADDREF(*_retval);
return NS_OK;
}
/* nsIImageRequest loadImageWithChannel(in nsIChannel, in nsIImageDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener); */
NS_IMETHODIMP nsImageLoader::LoadImageWithChannel(nsIChannel *channel, nsIImageDecoderObserver *aObserver, nsISupports *cx, nsIStreamListener **listener, nsIImageRequest **_retval)
{
NS_ASSERTION(channel, "nsImageLoader::LoadImageWithChannel -- NULL channel pointer");
nsImageRequest *imgRequest = nsnull;
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
ImageCache::Get(uri, &imgRequest);
if (imgRequest) {
// we have this in our cache already.. cancel the current (document) load
// XXX
// if *listener is null when we return here, the caller should probably cancel
// the channel instead of us doing it here.
channel->Cancel(NS_BINDING_ABORTED); // this should fire an OnStopRequest
*listener = nsnull; // give them back a null nsIStreamListener
} else {
#ifdef LOADER_THREADSAFE
nsAutoLock lock(mLock); // lock when we are adding things to the cache
#endif #endif
nsCOMPtr<nsIIOService> ioserv(do_GetService("@mozilla.org/network/io-service;1")); nsCOMPtr<nsIImageRequest> req(do_CreateInstance(kImageRequestCID));
if (!ioserv) return NS_ERROR_FAILURE;
nsCOMPtr<nsIChannel> newChannel; imgRequest = NS_REINTERPRET_CAST(nsImageRequest*, req.get());
ioserv->NewChannelFromURI(aURI, getter_AddRefs(newChannel)); NS_ADDREF(imgRequest);
if (!newChannel) return NS_ERROR_FAILURE;
newChannel->SetOwner(this); // the channel is now holding a strong ref to 'this' imgRequest->Init(channel);
// XXX look at the progid ImageCache::Put(uri, imgRequest);
nsCOMPtr<nsIImageRequest> imgRequest(do_CreateInstance("@mozilla.org/image/request;1"));
imgRequest->Init(newChannel);
#ifdef IMAGE_THREADPOOL *listener = NS_STATIC_CAST(nsIStreamListener*, imgRequest);
nsCOMPtr<nsIRunnable> run(do_QueryInterface(imgRequest)); NS_IF_ADDREF(*listener);
mThreadPool->DispatchRequest(run); }
#else
nsCOMPtr<nsIStreamListener> streamList(do_QueryInterface(imgRequest));
newChannel->AsyncRead(streamList, nsnull);
#endif
*_retval = imgRequest; nsCOMPtr<nsIImageRequest> proxyRequest(do_CreateInstance(kImageRequestProxyCID));
// init adds itself to imgRequest's list of observers
NS_REINTERPRET_CAST(nsImageRequestProxy*, proxyRequest.get())->Init(imgRequest, aObserver, cx);
NS_RELEASE(imgRequest);
*_retval = proxyRequest;
NS_ADDREF(*_retval); NS_ADDREF(*_retval);
return NS_OK; return NS_OK;

View File

@ -21,9 +21,13 @@
* Stuart Parmenter <pavlov@netscape.com> * Stuart Parmenter <pavlov@netscape.com>
*/ */
//#define LOADER_THREADSAFE 1
#include "nsIImageLoader.h" #include "nsIImageLoader.h"
#include "nsIThreadPool.h"
#include "nsCOMPtr.h" #ifdef LOADER_THREADSAFE
#include "prlock.h"
#endif
#define NS_IMAGELOADER_CID \ #define NS_IMAGELOADER_CID \
{ /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \ { /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \
@ -43,5 +47,7 @@ public:
virtual ~nsImageLoader(); virtual ~nsImageLoader();
private: private:
nsCOMPtr<nsIThreadPool> mThreadPool; #ifdef LOADER_THREADSAFE
PRLock *mLock;
#endif
}; };

View File

@ -35,18 +35,18 @@
#include "nsString.h" #include "nsString.h"
#include "nsIEventQueueService.h" #include "ImageCache.h"
#include "nsIEventQueue.h"
#include "nspr.h"
NS_IMPL_THREADSAFE_ISUPPORTS5(nsImageRequest, nsIImageRequest, nsIRequest, nsIStreamListener, nsIStreamObserver, nsIRunnable) NS_IMPL_ISUPPORTS5(nsImageRequest, nsIImageRequest,
nsIImageDecoderObserver, nsIImageContainerObserver,
nsIStreamListener, nsIStreamObserver)
nsImageRequest::nsImageRequest() nsImageRequest::nsImageRequest() :
mObservers(0), mProcessing(PR_TRUE), mStatus(nsIImageRequest::STATUS_NONE), mState(0)
{ {
NS_INIT_ISUPPORTS(); NS_INIT_ISUPPORTS();
/* member initializers and constructor code */ /* member initializers and constructor code */
mProcessing = PR_TRUE;
} }
nsImageRequest::~nsImageRequest() nsImageRequest::~nsImageRequest()
@ -55,12 +55,12 @@ nsImageRequest::~nsImageRequest()
} }
nsresult nsImageRequest::Init(nsIChannel *aChannel)
/* void init (in nsIChannel aChannel, in gfx_dimension width, in gfx_dimension height); */
NS_IMETHODIMP nsImageRequest::Init(nsIChannel *aChannel)
{ {
if (mImage) // XXX we should save off the thread we are getting called on here so that we can proxy all calls to mDecoder to it.
return NS_ERROR_FAILURE; // XXX
NS_ASSERTION(!mImage, "nsImageRequest::Init -- Multiple calls to init");
NS_ASSERTION(aChannel, "nsImageRequest::Init -- No channel");
mChannel = aChannel; mChannel = aChannel;
@ -70,6 +70,52 @@ NS_IMETHODIMP nsImageRequest::Init(nsIChannel *aChannel)
return NS_OK; return NS_OK;
} }
nsresult nsImageRequest::AddObserver(nsIImageDecoderObserver *observer)
{
mObservers.AppendElement(NS_STATIC_CAST(void*, observer));
if (mState & onStartDecode)
observer->OnStartDecode(nsnull, nsnull);
if (mState & onStartContainer)
observer->OnStartContainer(nsnull, nsnull, mImage);
// XXX send the decoded rect in here
if (mState & onStopContainer)
observer->OnStopContainer(nsnull, nsnull, mImage);
if (mState & onStopDecode)
observer->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
return NS_OK;
}
nsresult nsImageRequest::RemoveObserver(nsIImageDecoderObserver *observer, nsresult status)
{
mObservers.RemoveElement(NS_STATIC_CAST(void*, observer));
if ((mObservers.Count() == 0) && mChannel && mProcessing) {
mChannel->Cancel(status);
}
return NS_OK;
}
/** nsIImageRequest methods **/
/* void cancel (in nsresult status); */
NS_IMETHODIMP nsImageRequest::Cancel(nsresult status)
{
// XXX this method should not ever get called
nsresult rv = NS_OK;
if (mChannel && mProcessing) {
rv = mChannel->Cancel(status);
}
return rv;
}
/* readonly attribute nsIImage image; */ /* readonly attribute nsIImage image; */
NS_IMETHODIMP nsImageRequest::GetImage(nsIImageContainer * *aImage) NS_IMETHODIMP nsImageRequest::GetImage(nsIImageContainer * *aImage)
{ {
@ -78,113 +124,142 @@ NS_IMETHODIMP nsImageRequest::GetImage(nsIImageContainer * *aImage)
return NS_OK; return NS_OK;
} }
/* readonly attribute unsigned long imageStatus; */
NS_IMETHODIMP nsImageRequest::GetImageStatus(PRUint32 *aStatus)
/** nsIRequest methods **/
/* readonly attribute wstring name; */
NS_IMETHODIMP nsImageRequest::GetName(PRUnichar * *aName)
{ {
return mChannel->GetName(aName); *aStatus = mStatus;
} return NS_OK;
/* boolean isPending (); */
NS_IMETHODIMP nsImageRequest::IsPending(PRBool *_retval)
{
return mChannel->IsPending(_retval);
}
/* readonly attribute nsresult status; */
NS_IMETHODIMP nsImageRequest::GetStatus(nsresult *aStatus)
{
return mChannel->GetStatus(aStatus);
}
/* void cancel (in nsresult status); */
NS_IMETHODIMP nsImageRequest::Cancel(nsresult status)
{
return mChannel->Cancel(status);
}
/* void suspend (); */
NS_IMETHODIMP nsImageRequest::Suspend()
{
return mChannel->Suspend();
}
/* void resume (); */
NS_IMETHODIMP nsImageRequest::Resume()
{
return mChannel->Resume();
} }
/** nsIImageContainerObserver methods **/
/* [noscript] void frameChanged (in nsIImageContainer container, in nsISupports cx, in nsIImageFrame newframe, in nsRect dirtyRect); */
NS_IMETHODIMP nsImageRequest::FrameChanged(nsIImageContainer *container, nsISupports *cx, nsIImageFrame *newframe, nsRect * dirtyRect)
{
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->FrameChanged(container, cx, newframe, dirtyRect);
}
return NS_OK;
}
/** nsIImageDecoderObserver methods **/ /** nsIImageDecoderObserver methods **/
/* void onStartDecode (in nsIImageRequest request); */ /* void onStartDecode (in nsIImageRequest request, in nsISupports cx); */
NS_IMETHODIMP nsImageRequest::OnStartDecode(nsIImageRequest *request) NS_IMETHODIMP nsImageRequest::OnStartDecode(nsIImageRequest *request, nsISupports *cx)
{ {
if (mObserver) mState |= onStartDecode;
mObserver->OnStartDecode(this);
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnStartDecode(request, cx);
}
return NS_OK; return NS_OK;
} }
/* void onStartContainer (in nsIImageRequest request, in nsIImageContainer image); */ /* void onStartContainer (in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image); */
NS_IMETHODIMP nsImageRequest::OnStartContainer(nsIImageRequest *request, nsIImageContainer *image) NS_IMETHODIMP nsImageRequest::OnStartContainer(nsIImageRequest *request, nsISupports *cx, nsIImageContainer *image)
{ {
if (mObserver) mState |= onStartContainer;
mObserver->OnStartContainer(this, image);
mStatus |= nsIImageRequest::STATUS_SIZE_AVAILABLE;
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnStartContainer(request, cx, image);
}
return NS_OK; return NS_OK;
} }
/* void onStartFrame (in nsIImageRequest request, in nsIImageFrame frame); */ /* void onStartFrame (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame); */
NS_IMETHODIMP nsImageRequest::OnStartFrame(nsIImageRequest *request, nsIImageFrame *frame) NS_IMETHODIMP nsImageRequest::OnStartFrame(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame)
{ {
if (mObserver) PRInt32 i = -1;
mObserver->OnStartFrame(this, frame); PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnStartFrame(request, cx, frame);
}
return NS_OK; return NS_OK;
} }
/* [noscript] void onDataAvailable (in nsIImageRequest request, in nsIImageFrame frame, [const] in nsRect2 rect); */ /* [noscript] void onDataAvailable (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame, [const] in nsRect rect); */
NS_IMETHODIMP nsImageRequest::OnDataAvailable(nsIImageRequest *request, nsIImageFrame *frame, const nsRect2 * rect) NS_IMETHODIMP nsImageRequest::OnDataAvailable(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame, const nsRect * rect)
{ {
if (mObserver) PRInt32 i = -1;
mObserver->OnDataAvailable(this, frame, rect); PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnDataAvailable(request, cx, frame, rect);
}
return NS_OK; return NS_OK;
} }
/* void onStopFrame (in nsIImageRequest request, in nsIImageFrame frame); */ /* void onStopFrame (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame); */
NS_IMETHODIMP nsImageRequest::OnStopFrame(nsIImageRequest *request, nsIImageFrame *frame) NS_IMETHODIMP nsImageRequest::OnStopFrame(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame)
{ {
if (mObserver) PRInt32 i = -1;
mObserver->OnStopFrame(this, frame); PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnStopFrame(request, cx, frame);
}
return NS_OK; return NS_OK;
} }
/* void onStopContainer (in nsIImageRequest request, in nsIImageContainer image); */ /* void onStopContainer (in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image); */
NS_IMETHODIMP nsImageRequest::OnStopContainer(nsIImageRequest *request, nsIImageContainer *image) NS_IMETHODIMP nsImageRequest::OnStopContainer(nsIImageRequest *request, nsISupports *cx, nsIImageContainer *image)
{ {
if (mObserver) mState |= onStopContainer;
mObserver->OnStopContainer(this, image);
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnStopContainer(request, cx, image);
}
return NS_OK; return NS_OK;
} }
/* void onStopDecode (in nsIImageRequest request, in nsresult status, in wstring statusArg); */ /* void onStopDecode (in nsIImageRequest request, in nsISupports cx, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP nsImageRequest::OnStopDecode(nsIImageRequest *request, nsresult status, const PRUnichar *statusArg) NS_IMETHODIMP nsImageRequest::OnStopDecode(nsIImageRequest *request, nsISupports *cx, nsresult status, const PRUnichar *statusArg)
{ {
if (mObserver) mState |= onStopDecode;
mObserver->OnStopDecode(this, status, statusArg);
if (NS_FAILED(status))
mStatus = nsIImageRequest::STATUS_ERROR;
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
nsIImageDecoderObserver *ob = NS_STATIC_CAST(nsIImageDecoderObserver*, mObservers[i]);
if (ob) ob->OnStopDecode(request, cx, status, statusArg);
}
return NS_OK; return NS_OK;
} }
@ -199,13 +274,14 @@ NS_IMETHODIMP nsImageRequest::OnStopDecode(nsIImageRequest *request, nsresult st
/* void onStartRequest (in nsIChannel channel, in nsISupports ctxt); */ /* void onStartRequest (in nsIChannel channel, in nsISupports ctxt); */
NS_IMETHODIMP nsImageRequest::OnStartRequest(nsIChannel *channel, nsISupports *ctxt) NS_IMETHODIMP nsImageRequest::OnStartRequest(nsIChannel *channel, nsISupports *ctxt)
{ {
NS_ASSERTION(!mDecoder, "nsImageRequest::OnStartRequest -- we already have a decoder");
nsXPIDLCString contentType; nsXPIDLCString contentType;
channel->GetContentType(getter_Copies(contentType)); channel->GetContentType(getter_Copies(contentType));
printf("content type is %s\n", contentType.get()); printf("content type is %s\n", contentType.get());
nsCAutoString conid("@mozilla.org/image/decoder?"); nsCAutoString conid("@mozilla.org/image/decoder;2?type=");
conid += contentType.get(); conid += contentType.get();
conid += ";1";
mDecoder = do_CreateInstance(conid); mDecoder = do_CreateInstance(conid);
@ -225,11 +301,26 @@ NS_IMETHODIMP nsImageRequest::OnStartRequest(nsIChannel *channel, nsISupports *c
/* void onStopRequest (in nsIChannel channel, in nsISupports ctxt, in nsresult status, in wstring statusArg); */ /* void onStopRequest (in nsIChannel channel, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP nsImageRequest::OnStopRequest(nsIChannel *channel, nsISupports *ctxt, nsresult status, const PRUnichar *statusArg) NS_IMETHODIMP nsImageRequest::OnStopRequest(nsIChannel *channel, nsISupports *ctxt, nsresult status, const PRUnichar *statusArg)
{ {
NS_ASSERTION(mChannel || mProcessing, "nsImageRequest::OnStopRequest -- received multiple OnStopRequest");
mProcessing = PR_FALSE; mProcessing = PR_FALSE;
// if we failed, we should remove ourself from the cache
if (NS_FAILED(status)) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
ImageCache::Remove(uri);
}
mChannel = nsnull; // we no longer need the channel
if (!mDecoder) return NS_ERROR_FAILURE; if (!mDecoder) return NS_ERROR_FAILURE;
return mDecoder->Close(); mDecoder->Close();
mDecoder = nsnull; // release the decoder so that it can rest peacefully ;)
return NS_OK;
} }
@ -240,57 +331,11 @@ NS_IMETHODIMP nsImageRequest::OnStopRequest(nsIChannel *channel, nsISupports *ct
/* void onDataAvailable (in nsIChannel channel, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */ /* void onDataAvailable (in nsIChannel channel, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
NS_IMETHODIMP nsImageRequest::OnDataAvailable(nsIChannel *channel, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) NS_IMETHODIMP nsImageRequest::OnDataAvailable(nsIChannel *channel, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
{ {
if (!mDecoder) return NS_ERROR_FAILURE; if (!mDecoder) {
NS_ASSERTION(mDecoder, "nsImageRequest::OnDataAvailable -- no decoder");
return NS_ERROR_FAILURE;
}
PRUint32 wrote; PRUint32 wrote;
return mDecoder->WriteFrom(inStr, count, &wrote); return mDecoder->WriteFrom(inStr, count, &wrote);
} }
/** nsIRunnable methods **/
NS_IMETHODIMP nsImageRequest::Run()
{
nsresult rv = NS_OK;
if (!mChannel) return NS_ERROR_NOT_INITIALIZED;
// create an event queue for this thread.
nsCOMPtr<nsIEventQueueService> service = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = service->CreateThreadEventQueue();
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIEventQueue> currentThreadQ;
rv = service->GetThreadEventQueue(NS_CURRENT_THREAD,
getter_AddRefs(currentThreadQ));
if (NS_FAILED(rv)) return rv;
// initiate the AsyncRead from this thread so events are
// sent here for processing.
rv = mChannel->AsyncRead(NS_STATIC_CAST(nsIStreamListener*, this), nsnull);
if (NS_FAILED(rv)) return rv;
// process events until we're finished.
PLEvent *event;
while (mProcessing) {
rv = currentThreadQ->WaitForEvent(&event);
if (NS_FAILED(rv)) return rv;
rv = currentThreadQ->HandleEvent(event);
if (NS_FAILED(rv)) return rv;
}
rv = service->DestroyThreadEventQueue();
if (NS_FAILED(rv)) return rv;
// XXX make sure cleanup happens on the calling thread.
return NS_OK;
}

View File

@ -21,7 +21,10 @@
* Stuart Parmenter <pavlov@netscape.com> * Stuart Parmenter <pavlov@netscape.com>
*/ */
#include "nsIImageRequest.h" #ifndef nsImageRequest_h__
#define nsImageRequest_h__
#include "nsIImageRequest2.h"
#include "nsIRunnable.h" #include "nsIRunnable.h"
@ -32,6 +35,8 @@
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsVoidArray.h"
#define NS_IMAGEREQUEST_CID \ #define NS_IMAGEREQUEST_CID \
{ /* 9f733dd6-1dd1-11b2-8cdf-effb70d1ea71 */ \ { /* 9f733dd6-1dd1-11b2-8cdf-effb70d1ea71 */ \
0x9f733dd6, \ 0x9f733dd6, \
@ -40,28 +45,44 @@
{0x8c, 0xdf, 0xef, 0xfb, 0x70, 0xd1, 0xea, 0x71} \ {0x8c, 0xdf, 0xef, 0xfb, 0x70, 0xd1, 0xea, 0x71} \
} }
enum {
onStartDecode = 0x1,
onStartContainer = 0x2,
onStopContainer = 0x4,
onStopDecode = 0x8
};
class nsImageRequest : public nsIImageRequest, class nsImageRequest : public nsIImageRequest,
public nsIImageDecoderObserver, public nsIImageDecoderObserver,
public nsIStreamListener, public nsIRunnable public nsIStreamListener
{ {
public: public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIMAGEREQUEST
NS_DECL_NSIIMAGEDECODEROBSERVER
NS_DECL_NSIREQUEST
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSIRUNNABLE
nsImageRequest(); nsImageRequest();
virtual ~nsImageRequest(); virtual ~nsImageRequest();
/* additional members */ /* additional members */
nsresult Init(nsIChannel *aChannel);
nsresult AddObserver(nsIImageDecoderObserver *observer);
nsresult RemoveObserver(nsIImageDecoderObserver *observer, nsresult status);
NS_DECL_ISUPPORTS
NS_DECL_NSIIMAGEREQUEST
NS_DECL_NSIIMAGECONTAINEROBSERVER
NS_DECL_NSIIMAGEDECODEROBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
private: private:
nsCOMPtr<nsIChannel> mChannel; nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIImageContainer> mImage; nsCOMPtr<nsIImageContainer> mImage;
nsCOMPtr<nsIImageDecoder> mDecoder; nsCOMPtr<nsIImageDecoder> mDecoder;
nsCOMPtr<nsIImageDecoderObserver> mObserver;
nsVoidArray mObservers;
PRBool mProcessing; PRBool mProcessing;
PRUint32 mStatus;
PRUint32 mState;
}; };
#endif

View File

@ -0,0 +1,171 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsImageRequestProxy.h"
#include "nsXPIDLString.h"
#include "nsIInputStream.h"
#include "nsIImageLoader.h"
#include "nsIComponentManager.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsImageRequest.h"
#include "nsString.h"
#include "nsIChannel.h"
#include "nspr.h"
NS_IMPL_ISUPPORTS3(nsImageRequestProxy, nsIImageRequest, nsIImageDecoderObserver, nsIImageContainerObserver)
nsImageRequestProxy::nsImageRequestProxy()
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
}
nsImageRequestProxy::~nsImageRequestProxy()
{
/* destructor code */
NS_REINTERPRET_CAST(nsImageRequest*, mOwner.get())->RemoveObserver(this, NS_ERROR_FAILURE); // XXX bogus result value
}
nsresult nsImageRequestProxy::Init(nsImageRequest *request, nsIImageDecoderObserver *aObserver, nsISupports *cx)
{
PR_ASSERT(request);
mOwner = NS_STATIC_CAST(nsIImageRequest*, request);
mObserver = aObserver;
// XXX we should save off the thread we are getting called on here so that we can proxy all calls to mDecoder to it.
mContext = cx;
request->AddObserver(this);
return NS_OK;
}
/* void cancel (in nsresult status); */
NS_IMETHODIMP nsImageRequestProxy::Cancel(nsresult status)
{
return NS_REINTERPRET_CAST(nsImageRequest*, mOwner.get())->RemoveObserver(this, status);
}
/* readonly attribute nsIImage image; */
NS_IMETHODIMP nsImageRequestProxy::GetImage(nsIImageContainer * *aImage)
{
return mOwner->GetImage(aImage);
}
/* readonly attribute unsigned long imageStatus; */
NS_IMETHODIMP nsImageRequestProxy::GetImageStatus(PRUint32 *aStatus)
{
return mOwner->GetImageStatus(aStatus);
}
/** nsIImageContainerObserver methods **/
/* [noscript] void frameChanged (in nsIImageContainer container, in nsISupports cx, in nsIImageFrame newframe, in nsRect dirtyRect); */
NS_IMETHODIMP nsImageRequestProxy::FrameChanged(nsIImageContainer *container, nsISupports *cx, nsIImageFrame *newframe, nsRect * dirtyRect)
{
if (mObserver)
mObserver->FrameChanged(container, mContext, newframe, dirtyRect);
return NS_OK;
}
/** nsIImageDecoderObserver methods **/
/* void onStartDecode (in nsIImageRequest request, in nsISupports cx); */
NS_IMETHODIMP nsImageRequestProxy::OnStartDecode(nsIImageRequest *request, nsISupports *cx)
{
if (mObserver)
mObserver->OnStartDecode(this, mContext);
return NS_OK;
}
/* void onStartContainer (in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image); */
NS_IMETHODIMP nsImageRequestProxy::OnStartContainer(nsIImageRequest *request, nsISupports *cx, nsIImageContainer *image)
{
if (mObserver)
mObserver->OnStartContainer(this, mContext, image);
return NS_OK;
}
/* void onStartFrame (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame); */
NS_IMETHODIMP nsImageRequestProxy::OnStartFrame(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame)
{
if (mObserver)
mObserver->OnStartFrame(this, mContext, frame);
return NS_OK;
}
/* [noscript] void onDataAvailable (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame, [const] in nsRect rect); */
NS_IMETHODIMP nsImageRequestProxy::OnDataAvailable(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame, const nsRect * rect)
{
if (mObserver)
mObserver->OnDataAvailable(this, mContext, frame, rect);
return NS_OK;
}
/* void onStopFrame (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame); */
NS_IMETHODIMP nsImageRequestProxy::OnStopFrame(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame)
{
if (mObserver)
mObserver->OnStopFrame(this, mContext, frame);
return NS_OK;
}
/* void onStopContainer (in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image); */
NS_IMETHODIMP nsImageRequestProxy::OnStopContainer(nsIImageRequest *request, nsISupports *cx, nsIImageContainer *image)
{
if (mObserver)
mObserver->OnStopContainer(this, mContext, image);
return NS_OK;
}
/* void onStopDecode (in nsIImageRequest request, in nsISupports cx, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP nsImageRequestProxy::OnStopDecode(nsIImageRequest *request, nsISupports *cx, nsresult status, const PRUnichar *statusArg)
{
if (mObserver)
mObserver->OnStopDecode(this, mContext, status, statusArg);
return NS_OK;
}

View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsImageRequest.h"
#include "nsIImageDecoderObserver.h"
#include "nsIImageContainer.h"
#include "nsIImageDecoder.h"
#include "nsCOMPtr.h"
#define NS_IMAGEREQUESTPROXY_CID \
{ /* 20557898-1dd2-11b2-8f65-9c462ee2bc95 */ \
0x20557898, \
0x1dd2, \
0x11b2, \
{0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95} \
}
class nsImageRequestProxy : public nsIImageRequest,
public nsIImageDecoderObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIMAGEREQUEST
NS_DECL_NSIIMAGEDECODEROBSERVER
NS_DECL_NSIIMAGECONTAINEROBSERVER
nsImageRequestProxy();
virtual ~nsImageRequestProxy();
/* additional members */
nsresult Init(nsImageRequest *request, nsIImageDecoderObserver *aObserver, nsISupports *cx);
private:
nsCOMPtr<nsIImageDecoderObserver> mObserver;
nsCOMPtr<nsISupports> mContext;
nsCOMPtr<nsIImageRequest> mOwner;
};