diff --git a/modules/libpr0n/.cvsignore b/modules/libpr0n/.cvsignore new file mode 100644 index 000000000000..bd5fe06963c7 --- /dev/null +++ b/modules/libpr0n/.cvsignore @@ -0,0 +1,2 @@ +Makefile +.deps diff --git a/modules/libpr0n/decoders/Makefile.in b/modules/libpr0n/decoders/Makefile.in index f99e136a9d97..5d8e619e57f7 100644 --- a/modules/libpr0n/decoders/Makefile.in +++ b/modules/libpr0n/decoders/Makefile.in @@ -26,7 +26,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = ppm png +DIRS = ppm png gif jpeg include $(topsrcdir)/config/rules.mk diff --git a/modules/libpr0n/decoders/jpeg/.cvsignore b/modules/libpr0n/decoders/jpeg/.cvsignore new file mode 100644 index 000000000000..bd5fe06963c7 --- /dev/null +++ b/modules/libpr0n/decoders/jpeg/.cvsignore @@ -0,0 +1,2 @@ +Makefile +.deps diff --git a/modules/libpr0n/decoders/jpeg/Makefile.in b/modules/libpr0n/decoders/jpeg/Makefile.in new file mode 100644 index 000000000000..395fa492f2b1 --- /dev/null +++ b/modules/libpr0n/decoders/jpeg/Makefile.in @@ -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 + diff --git a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp index 26f3a5bb7356..77f4f40f40b2 100644 --- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp +++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp @@ -28,10 +28,12 @@ #include "nspr.h" -#include "nsUnitConverters.h" - #include "nsCRT.h" +#include "nsIComponentManager.h" + +#include "nsIImageContainerObserver.h" + 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. */ #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 */ @@ -59,26 +53,8 @@ typedef struct { /* public fields; must be first in this struct! */ struct jpeg_source_mgr pub; - 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; @@ -88,10 +64,8 @@ nsJPEGDecoder::nsJPEGDecoder() mState = JPEG_HEADER; - mBuf = nsnull; - mBufLen = 0; + mDataLen = 0; - mCurDataLen = 0; mSamples = nsnull; mSamples3 = nsnull; @@ -110,15 +84,22 @@ nsJPEGDecoder::~nsJPEGDecoder() NS_IMETHODIMP nsJPEGDecoder::Init(nsIImageRequest *aRequest) { mRequest = aRequest; + mObserver = do_QueryInterface(mRequest); 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 */ /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&mInfo); + + /* Step 2: specify data source (eg, a file) */ decoder_source_mgr *src; if (mInfo.src == NULL) { @@ -181,15 +162,12 @@ NS_IMETHODIMP nsJPEGDecoder::GetRequest(nsIImageRequest * *aRequest) /* void close (); */ NS_IMETHODIMP nsJPEGDecoder::Close() { + + // XXX this should flush the data out + + // XXX progressive? ;) - 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. - */ +// OutputScanlines(mInfo.output_height); /* 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. */ jpeg_destroy_decompress(&mInfo); - - - - printf("nsJPEGDecoder::Close()\n"); - - - PR_FREEIF(mBuf); - - return NS_OK; } @@ -230,44 +199,25 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR */ // XXX above what is this? - PRUint32 readLen; - - if (!mBuf) { - mBuf = (char*)PR_Malloc(count); - mBufLen = count; + if (inStr) { + mOutStream->WriteFrom(inStr, count, _retval); + mDataLen += *_retval; } - - 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); - if (!mSamples && jpeg_read_header(&mInfo, TRUE) != JPEG_SUSPENDED) { - - - /* FIXME -- Should reset dct_method and dither mode - * for final pass of progressive JPEG - */ - mInfo.dct_method = JDCT_FASTEST; - mInfo.dither_mode = JDITHER_ORDERED; - mInfo.do_fancy_upsampling = FALSE; - mInfo.enable_2pass_quant = FALSE; - mInfo.do_block_smoothing = TRUE; + int status; + switch (mState) { + case JPEG_HEADER: + { + /* Step 3: read file parameters with jpeg_read_header() */ + if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) + return NS_OK; /* * 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 */ 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); } - } else { - return NS_OK; + mState = JPEG_START_DECOMPRESS; } + case JPEG_START_DECOMPRESS: + /* Step 4: set parameters for decompression */ - /* Step 3: read file parameters with jpeg_read_header() */ -// (void) jpeg_read_header(&mInfo, TRUE); - /* We can ignore the return value from jpeg_read_header since - * (a) suspension is not possible with the stdio data source, and - * (b) we passed TRUE to reject a tables-only JPEG file as an error. - * See libjpeg.doc for more info. - */ + /* FIXME -- Should reset dct_method and dither mode + * for final pass of progressive JPEG + */ + mInfo.dct_method = JDCT_FASTEST; + mInfo.dither_mode = JDITHER_ORDERED; + 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 - * jpeg_read_header(), so we do nothing here. - */ + /* Step 5: Start decompressor */ + if (jpeg_start_decompress(&mInfo) == FALSE) + return NS_OK; - /* Step 5: Start decompressor */ + mState = JPEG_DECOMPRESS_PROGRESSIVE; - (void) jpeg_start_decompress(&mInfo); - /* We can ignore the return value since suspension is not possible - * with the stdio data source. - */ + case JPEG_DECOMPRESS_PROGRESSIVE: + do { + status = jpeg_consume_input(&mInfo); + } while (!((status == JPEG_SUSPENDED) || + (status == JPEG_REACHED_EOI))); - int status; - do { - status = jpeg_consume_input(&mInfo); - } while (!((status == JPEG_SUSPENDED) || - (status == JPEG_REACHED_EOI))); + if (status == JPEG_REACHED_EOI) { + mState = JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT; + } else { + return NS_OK; + } + + 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 * 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); /* 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 @@ -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 ic->imgdcb->ImgDCBHaveRow( 0, samples, 0, mInfo.output_width, mInfo.output_scanline-1, 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 * 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 * 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 fill_input_buffer (j_decompress_ptr jd) { decoder_source_mgr *src = (decoder_source_mgr *)jd->src; - return src->decoder->FillInput(jd); -} + PRUint32 _retval; -PRBool nsJPEGDecoder::FillInput(j_decompress_ptr jd) -{ - // read the data from the input stram... - - decoder_source_mgr *src = (decoder_source_mgr *)jd->src; - - if (mCurDataLen == 0) - 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; + if (src->decoder->mBytesToSkip != 0) { + if (src->decoder->mBytesToSkip > src->decoder->mDataLen){ + src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd), + src->decoder->mDataLen, &_retval); + } else { + src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd), + src->decoder->mBytesToSkip, &_retval); } - - suspend: -// 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; + src->decoder->mBytesToSkip -= _retval; + src->decoder->mDataLen -= _retval; } + + 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 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 newline at end of file +} diff --git a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h index d6eb7b2be35e..a9ece19a84c4 100644 --- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h +++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h @@ -28,12 +28,17 @@ #include "nsCOMPtr.h" -#include "nsIImage2.h" -#include "nsIImageRequest.h" +#include "nsIImageContainer.h" +#include "nsIImageFrame.h" +#include "nsIImageDecoderObserver.h" +#include "nsIImageRequest2.h" #include "nsIInputStream.h" +#include "nsIPipe.h" #include "jpeglib.h" +#include + #define NS_JPEGDECODER_CID \ { /* 5871a422-1dd2-11b2-ab3f-e2e56be5da9c */ \ 0x5871a422, \ @@ -77,18 +82,21 @@ public: protected: int OutputScanlines(int num_scanlines); -private: - nsCOMPtr mImage; +public: + nsCOMPtr mImage; + nsCOMPtr mFrame; nsCOMPtr mRequest; - nsCOMPtr mStream; + + nsCOMPtr mObserver; struct jpeg_decompress_struct mInfo; decoder_error_mgr mErr; jstate mState; - char *mBuf; - PRUint32 mBufLen; - PRUint32 mCurDataLen; + nsCOMPtr mInStream; + nsCOMPtr mOutStream; + + PRUint32 mDataLen; JSAMPARRAY mSamples; JSAMPARRAY mSamples3; diff --git a/modules/libpr0n/decoders/jpeg/nsJPEGFactory.cpp b/modules/libpr0n/decoders/jpeg/nsJPEGFactory.cpp index ee1d7ddc8720..5c62ca852ba8 100644 --- a/modules/libpr0n/decoders/jpeg/nsJPEGFactory.cpp +++ b/modules/libpr0n/decoders/jpeg/nsJPEGFactory.cpp @@ -34,7 +34,7 @@ static nsModuleComponentInfo components[] = { { "ppm decoder", NS_JPEGDECODER_CID, - "@mozilla.org/image/decoder?image/jpeg;1", + "@mozilla.org/image/decoder;2?type=image/jpeg", nsJPEGDecoderConstructor, }, }; diff --git a/modules/libpr0n/decoders/makefile.win b/modules/libpr0n/decoders/makefile.win index 79dfba462531..9e7bd0b1105c 100644 --- a/modules/libpr0n/decoders/makefile.win +++ b/modules/libpr0n/decoders/makefile.win @@ -21,6 +21,6 @@ DEPTH=..\..\.. -DIRS = ppm png +DIRS = ppm gif png jpeg !include $(DEPTH)\config\rules.mak diff --git a/modules/libpr0n/decoders/png/makefile.win b/modules/libpr0n/decoders/png/makefile.win index 74e820b6414d..1f44bfafb811 100644 --- a/modules/libpr0n/decoders/png/makefile.win +++ b/modules/libpr0n/decoders/png/makefile.win @@ -39,6 +39,7 @@ LLIBS=\ $(DIST)\lib\xpcom.lib \ $(DIST)\lib\png.lib \ $(DIST)\lib\zlib.lib \ + $(DIST)\lib\gkgfxwin.lib \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp index aac3a739ffe2..34942e6171b9 100644 --- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp +++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp @@ -34,6 +34,11 @@ #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. @@ -47,11 +52,19 @@ nsPNGDecoder::nsPNGDecoder() mPNG = nsnull; mInfo = nsnull; + colorLine = 0; + alphaLine = 0; + interlacebuf = 0; } 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) */ - 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; } @@ -136,6 +149,17 @@ static NS_METHOD ReadDataOut(nsIInputStream* in, PRUint32 *writeCount) { 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); 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); */ NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_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; - } +// PRUint32 sourceOffset = *_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)); 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 - decoder->mImage->Init(width, height); + decoder->mImage->Init(width, height, 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"); #if 0 @@ -328,21 +343,44 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) return NS_ERROR_FAILURE; #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); 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 (channels == 3) { - decoder->mFrame->Init(0, 0, width, height, nsIGFXFormat::RGB); - } else if (channels > 3) { - if (alpha_bits == 8) { - decoder->mFrame->Init(0, 0, width, height, nsIGFXFormat::RGBA); - } else if (alpha_bits == 1) { - decoder->mFrame->Init(0, 0, width, height, nsIGFXFormat::RGB_A1); - } + if (interlace_type == PNG_INTERLACE_ADAM7) { + decoder->interlacebuf = (PRUint8 *)nsMemory::Alloc(channels*width*height); + decoder->ibpr = channels*width; + if (!decoder->interlacebuf) { +// return NS_ERROR_FAILURE; + } } 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)); - PRUint32 bpr; - decoder->mFrame->GetBytesPerRow(&bpr); + PRUint32 bpr, abpr; + decoder->mFrame->GetImageBytesPerRow(&bpr); + decoder->mFrame->GetAlphaBytesPerRow(&abpr); PRUint32 length; PRUint8 *bits; - decoder->mFrame->GetBits(&bits, &length); + decoder->mFrame->GetImageData(&bits, &length); png_bytep line; - if (bits) { - line = bits+(row_num*bpr); + if (decoder->interlacebuf) { + line = decoder->interlacebuf+(row_num*decoder->ibpr); png_progressive_combine_row(png_ptr, line, new_row); } else line = 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>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; xmFrame->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)); if (decoder->mObserver) { - decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame); - decoder->mObserver->OnStopContainer(nsnull, decoder->mImage); - decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull); + decoder->mObserver->OnStopFrame(nsnull, nsnull, decoder->mFrame); + decoder->mObserver->OnStopContainer(nsnull, nsnull, decoder->mImage); + decoder->mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull); } } diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.h b/modules/libpr0n/decoders/png/nsPNGDecoder.h index 3879b3e6f244..01a1012cc507 100644 --- a/modules/libpr0n/decoders/png/nsPNGDecoder.h +++ b/modules/libpr0n/decoders/png/nsPNGDecoder.h @@ -29,7 +29,7 @@ #include "nsIImageContainer.h" #include "nsIImageDecoderObserver.h" #include "nsIImageFrame.h" -#include "nsIImageRequest.h" +#include "nsIImageRequest2.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); -private: +public: nsCOMPtr mImage; nsCOMPtr mFrame; nsCOMPtr mRequest; @@ -74,6 +74,9 @@ private: png_structp mPNG; png_infop mInfo; + PRUint8 *colorLine, *alphaLine; + PRUint8 *interlacebuf; + PRUint32 ibpr; }; #endif // nsPNGDecoder_h__ diff --git a/modules/libpr0n/decoders/png/nsPNGFactory.cpp b/modules/libpr0n/decoders/png/nsPNGFactory.cpp index 7495831dfa5d..82c34ea3ccea 100644 --- a/modules/libpr0n/decoders/png/nsPNGFactory.cpp +++ b/modules/libpr0n/decoders/png/nsPNGFactory.cpp @@ -34,7 +34,11 @@ static nsModuleComponentInfo components[] = { { "PNG decoder", 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, }, }; diff --git a/modules/libpr0n/decoders/ppm/makefile.win b/modules/libpr0n/decoders/ppm/makefile.win index 13465fbe9210..381e75ce63d0 100644 --- a/modules/libpr0n/decoders/ppm/makefile.win +++ b/modules/libpr0n/decoders/ppm/makefile.win @@ -37,6 +37,7 @@ OBJS = \ LLIBS=\ $(LIBNSPR) \ $(DIST)\lib\xpcom.lib \ + $(DIST)\lib\gkgfxwin.lib \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/modules/libpr0n/decoders/ppm/nsPPMDecoder.cpp b/modules/libpr0n/decoders/ppm/nsPPMDecoder.cpp index b9554f61cfb6..80132e066896 100644 --- a/modules/libpr0n/decoders/ppm/nsPPMDecoder.cpp +++ b/modules/libpr0n/decoders/ppm/nsPPMDecoder.cpp @@ -20,23 +20,20 @@ * Contributor(s): * Stuart Parmenter * - * - * the ppm decoding function is from Tim Rowley - * i dunno its license - * */ #include "nsPPMDecoder.h" #include "nsIInputStream.h" #include "nsIImageContainer.h" +#include "nsIImageContainerObserver.h" #include "nspr.h" -#include "nsUnitConverters.h" - #include "nsIComponentManager.h" +#include "nsRect.h" + NS_IMPL_ISUPPORTS2(nsPPMDecoder, nsIImageDecoder, nsIOutputStream) @@ -63,15 +60,14 @@ NS_IMETHODIMP nsPPMDecoder::Init(nsIImageRequest *aRequest) { mRequest = aRequest; - nsCOMPtr container; - aRequest->GetImage(getter_AddRefs(container)); + mObserver = do_QueryInterface(aRequest); // we're holding 2 strong refs to the request. - mImage = do_CreateInstance("@mozilla.org/gfx/image/frame;2"); - if (!mImage) + aRequest->GetImage(getter_AddRefs(mImage)); + + mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2"); + if (!mFrame) return NS_ERROR_FAILURE; - container->AppendFrame(mImage); - return NS_OK; } @@ -93,11 +89,11 @@ NS_IMETHODIMP nsPPMDecoder::GetRequest(nsIImageRequest * *aRequest) /* void close (); */ NS_IMETHODIMP nsPPMDecoder::Close() { - printf("nsPPMDecoder::Close()\n"); - - // XXX hack - gfx_format format; - mImage->GetFormat(&format); + if (mObserver) { + mObserver->OnStopFrame(nsnull, nsnull, mFrame); + mObserver->OnStopContainer(nsnull, nsnull, mImage); + mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull); + } return NS_OK; } @@ -185,6 +181,8 @@ NS_IMETHODIMP nsPPMDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRU if (mDataReceived == 0) { + mObserver->OnStartDecode(nsnull, nsnull); + // Check the magic number char type; 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; 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(0, 0, w, h, nsIGFXFormat::RGB); + mImage->Init(w, h, mObserver); + 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; - gfx_dimension width; - mImage->GetBytesPerRow(&bpr); - mImage->GetWidth(&width); + nscoord width; + mFrame->GetImageBytesPerRow(&bpr); + mFrame->GetWidth(&width); - PRUint32 real_bpr = GFXCoordToIntCeil(width) * 3; + // XXX ceil? + PRUint32 real_bpr = width * 3; PRUint32 i = 0; 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 { 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 ; i++; } while(dataLen >= real_bpr * (i+1)); diff --git a/modules/libpr0n/decoders/ppm/nsPPMDecoder.h b/modules/libpr0n/decoders/ppm/nsPPMDecoder.h index 8300abef2ad7..f14c2d8897f3 100644 --- a/modules/libpr0n/decoders/ppm/nsPPMDecoder.h +++ b/modules/libpr0n/decoders/ppm/nsPPMDecoder.h @@ -28,8 +28,10 @@ #include "nsCOMPtr.h" +#include "nsIImageContainer.h" +#include "nsIImageDecoderObserver.h" #include "nsIImageFrame.h" -#include "nsIImageRequest.h" +#include "nsIImageRequest2.h" #define NS_PPMDECODER_CID \ { /* e90bfa06-1dd1-11b2-8217-f38fe5d431a2 */ \ @@ -50,8 +52,11 @@ public: virtual ~nsPPMDecoder(); private: - nsCOMPtr mImage; + nsCOMPtr mImage; + nsCOMPtr mFrame; nsCOMPtr mRequest; + nsCOMPtr mObserver; // this is just qi'd from mRequest for speed + PRUint32 mDataReceived; PRUint32 mDataWritten; diff --git a/modules/libpr0n/decoders/ppm/nsPPMFactory.cpp b/modules/libpr0n/decoders/ppm/nsPPMFactory.cpp index 38009a7a9cbd..022ad74a0de8 100644 --- a/modules/libpr0n/decoders/ppm/nsPPMFactory.cpp +++ b/modules/libpr0n/decoders/ppm/nsPPMFactory.cpp @@ -34,7 +34,7 @@ static nsModuleComponentInfo components[] = { { "ppm decoder", NS_PPMDECODER_CID, - "@mozilla.org/image/decoder?image/x-portable-pixmap;1", + "@mozilla.org/image/decoder;2?type=image/x-portable-pixmap", nsPPMDecoderConstructor, }, }; diff --git a/modules/libpr0n/macbuild/libimg2.mcp b/modules/libpr0n/macbuild/libimg2.mcp index 00bcc1628a40..b9cbad823edc 100644 Binary files a/modules/libpr0n/macbuild/libimg2.mcp and b/modules/libpr0n/macbuild/libimg2.mcp differ diff --git a/modules/libpr0n/public/.cvsignore b/modules/libpr0n/public/.cvsignore new file mode 100644 index 000000000000..909f84cf9399 --- /dev/null +++ b/modules/libpr0n/public/.cvsignore @@ -0,0 +1,3 @@ +Makefile +.deps +_xpidlgen diff --git a/modules/libpr0n/public/MANIFEST_IDL b/modules/libpr0n/public/MANIFEST_IDL new file mode 100644 index 000000000000..2b06ac3d38b6 --- /dev/null +++ b/modules/libpr0n/public/MANIFEST_IDL @@ -0,0 +1,4 @@ +nsIImageDecoder.idl +nsIImageDecoderObserver.idl +nsIImageLoader.idl +nsIImageRequest2.idl diff --git a/modules/libpr0n/public/Makefile.in b/modules/libpr0n/public/Makefile.in index 598fdda859df..c26eda643cfa 100644 --- a/modules/libpr0n/public/Makefile.in +++ b/modules/libpr0n/public/Makefile.in @@ -31,7 +31,7 @@ MODULE = imglib2 XPIDLSRCS = nsIImageDecoder.idl \ nsIImageDecoderObserver.idl \ nsIImageLoader.idl \ - nsIImageRequest.idl + nsIImageRequest2.idl include $(topsrcdir)/config/rules.mk diff --git a/modules/libpr0n/public/makefile.win b/modules/libpr0n/public/makefile.win index 25a1db824905..3feac563f91c 100644 --- a/modules/libpr0n/public/makefile.win +++ b/modules/libpr0n/public/makefile.win @@ -31,7 +31,7 @@ XPIDLSRCS = \ .\nsIImageDecoder.idl \ .\nsIImageDecoderObserver.idl \ .\nsIImageLoader.idl \ - .\nsIImageRequest.idl \ + .\nsIImageRequest2.idl \ $(NULL) diff --git a/modules/libpr0n/public/nsIImageDecoder.idl b/modules/libpr0n/public/nsIImageDecoder.idl index fd5029f36b87..62d9d5121139 100644 --- a/modules/libpr0n/public/nsIImageDecoder.idl +++ b/modules/libpr0n/public/nsIImageDecoder.idl @@ -27,9 +27,25 @@ interface nsIImageRequest; +/** + * nsIImageDecoder interface + * + * @author Stuart Parmenter + * @version 0.1 + * @see imagelib2 + */ [scriptable, uuid(9eebf43a-1dd1-11b2-953e-f1782f4cbad3)] 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); /// allows access to the nsIImage we have to put bits in to. diff --git a/modules/libpr0n/public/nsIImageDecoderObserver.idl b/modules/libpr0n/public/nsIImageDecoderObserver.idl index d35f43ab87de..86ba112515ca 100644 --- a/modules/libpr0n/public/nsIImageDecoderObserver.idl +++ b/modules/libpr0n/public/nsIImageDecoderObserver.idl @@ -21,13 +21,17 @@ * Stuart Parmenter */ -#include "nsISupports.idl" +#include "nsIImageContainerObserver.idl" #include "gfxtypes.idl" interface nsIImageRequest; interface nsIImageContainer; interface nsIImageFrame; +%{C++ +#include "nsRect.h" +%} + /** * nsIImageDecoderObserver interface * @@ -36,42 +40,42 @@ interface nsIImageFrame; * @see imagelib2 */ [scriptable, uuid(350163d2-1dd2-11b2-9e69-89959ecec1f3)] -interface nsIImageDecoderObserver : nsISupports +interface nsIImageDecoderObserver : nsIImageContainerObserver { /** * 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 */ - 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 */ - 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 */ - [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 */ - 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 */ - 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 */ - 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); }; diff --git a/modules/libpr0n/public/nsIImageLoader.idl b/modules/libpr0n/public/nsIImageLoader.idl index 4da0bfbd3360..4ca4d81a58e5 100644 --- a/modules/libpr0n/public/nsIImageLoader.idl +++ b/modules/libpr0n/public/nsIImageLoader.idl @@ -24,19 +24,42 @@ #include "nsISupports.idl" #include "gfxtypes.idl" -interface nsIImage; +interface nsIImageDecoderObserver; interface nsIImageRequest; interface nsISimpleEnumerator; +interface nsIStreamListener; interface nsIURI; +interface nsIChannel; +/** + * nsIImageLoader interface + * + * @author Stuart Parmenter + * @version 0.1 + * @see imagelib2 + */ [scriptable, uuid(4c8cf1e0-1dd2-11b2-aff9-c51cdbfcb6da)] 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. - * Enumerator element type: nsIImageRequest. + * @note Enumerator element type: nsIImageRequest. */ readonly attribute nsISimpleEnumerator requests; }; diff --git a/modules/libpr0n/public/nsIImageRequest.idl b/modules/libpr0n/public/nsIImageRequest2.idl similarity index 60% rename from modules/libpr0n/public/nsIImageRequest.idl rename to modules/libpr0n/public/nsIImageRequest2.idl index bc78cee2d1c5..f9d3f25ba693 100644 --- a/modules/libpr0n/public/nsIImageRequest.idl +++ b/modules/libpr0n/public/nsIImageRequest2.idl @@ -22,23 +22,42 @@ */ #include "nsISupports.idl" -#include "nsIRequest.idl" -#include "gfxtypes.idl" -interface nsIChannel; interface nsIImageContainer; +/** + * nsIImageRequest interface + * + * @author Stuart Parmenter + * @version 0.1 + * @see imagelib2 + */ [scriptable, uuid(ccf705f6-1dd1-11b2-82ef-e18eccf7f7ec)] -interface nsIImageRequest : nsIRequest +interface nsIImageRequest : nsISupports { - // const values for GetStatus() to be used someday... - // const long STATUS_NONE = 0x0; - // const long STATUS_SIZE_AVAILABLE = 0x1; - // const long STATUS_IMAGE_READY = 0x2; - // const long STATUS_ERROR = 0x4; + void cancel(in nsresult status); - void init(in nsIChannel aChannel); - - /// @return the image object associated with the request. + /** + * the image container... + * @return the image object associated with the request. + * @attention NEED DOCS + */ 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; }; diff --git a/modules/libpr0n/src/.cvsignore b/modules/libpr0n/src/.cvsignore new file mode 100644 index 000000000000..bd5fe06963c7 --- /dev/null +++ b/modules/libpr0n/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +.deps diff --git a/modules/libpr0n/src/ImageCache.cpp b/modules/libpr0n/src/ImageCache.cpp new file mode 100644 index 000000000000..b3f5bf581290 --- /dev/null +++ b/modules/libpr0n/src/ImageCache.cpp @@ -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 + */ + +#include "ImageCache.h" + +#include "nsXPIDLString.h" +#include "nsCOMPtr.h" + +#include "nsHashtable.h" + +class nsIURIKey : public nsHashKey { +protected: + nsCOMPtr 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); +} diff --git a/modules/libpr0n/src/ImageCache.h b/modules/libpr0n/src/ImageCache.h new file mode 100644 index 000000000000..6453183ef5b2 --- /dev/null +++ b/modules/libpr0n/src/ImageCache.h @@ -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 + */ + +#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 diff --git a/modules/libpr0n/src/Makefile.in b/modules/libpr0n/src/Makefile.in index 0916e4fd0bfa..7c7f12f8af6a 100644 --- a/modules/libpr0n/src/Makefile.in +++ b/modules/libpr0n/src/Makefile.in @@ -30,9 +30,11 @@ MODULE = imglib2 LIBRARY_NAME = imglib2 IS_COMPONENT = 1 -CPPSRCS = nsImageFactory.cpp \ - nsImageLoader.cpp \ - nsImageRequest.cpp +CPPSRCS = ImageCache.cpp \ + nsImageFactory.cpp \ + nsImageLoader.cpp \ + nsImageRequest.cpp \ + nsImageRequestProxy.cpp EXTRA_DSO_LDOPTS = \ $(MOZ_COMPONENT_LIBS) \ diff --git a/modules/libpr0n/src/makefile.win b/modules/libpr0n/src/makefile.win index ba7ec1ba0183..c81ceb8e7b29 100644 --- a/modules/libpr0n/src/makefile.win +++ b/modules/libpr0n/src/makefile.win @@ -30,8 +30,10 @@ DLL = $(OBJDIR)\$(LIBRARY_NAME).dll MAKE_OBJ_TYPE = DLL OBJS = \ + .\$(OBJDIR)\ImageCache.obj \ .\$(OBJDIR)\nsImageLoader.obj \ .\$(OBJDIR)\nsImageRequest.obj \ + .\$(OBJDIR)\nsImageRequestProxy.obj \ .\$(OBJDIR)\nsImageFactory.obj \ $(NULL) diff --git a/modules/libpr0n/src/nsImageFactory.cpp b/modules/libpr0n/src/nsImageFactory.cpp index bc6e6ae18a46..5130ac64a555 100644 --- a/modules/libpr0n/src/nsImageFactory.cpp +++ b/modules/libpr0n/src/nsImageFactory.cpp @@ -26,11 +26,13 @@ #include "nsImageLoader.h" #include "nsImageRequest.h" +#include "nsImageRequestProxy.h" // objects that just require generic constructors NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageLoader) NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageRequest) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageRequestProxy) static nsModuleComponentInfo components[] = { @@ -40,9 +42,12 @@ static nsModuleComponentInfo components[] = nsImageLoaderConstructor, }, { "image request", NS_IMAGEREQUEST_CID, - "@mozilla.org/image/request;1", + "@mozilla.org/image/request/real;1", nsImageRequestConstructor, }, - + { "image request proxy", + NS_IMAGEREQUESTPROXY_CID, + "@mozilla.org/image/request/proxy;1", + nsImageRequestProxyConstructor, }, }; NS_IMPL_NSGETMODULE("nsImageLib2Module", components) diff --git a/modules/libpr0n/src/nsImageLoader.cpp b/modules/libpr0n/src/nsImageLoader.cpp index a5b1e7b7630b..6a748628416d 100644 --- a/modules/libpr0n/src/nsImageLoader.cpp +++ b/modules/libpr0n/src/nsImageLoader.cpp @@ -23,7 +23,7 @@ #include "nsImageLoader.h" -#include "nsIImageRequest.h" +#include "nsIImageRequest2.h" #include "nsIServiceManager.h" @@ -33,57 +33,136 @@ #include "nsIStreamListener.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) +#endif nsImageLoader::nsImageLoader() { NS_INIT_ISUPPORTS(); /* member initializers and constructor code */ +#ifdef LOADER_THREADSAFE + mLock = PR_NewLock(); +#endif } nsImageLoader::~nsImageLoader() { /* destructor code */ +#ifdef LOADER_THREADSAFE + PR_DestroyLock(mLock); +#endif } -//#define IMAGE_THREADPOOL 1 - -/* nsIImageRequest loadImage (in nsIURI uri, in gfx_dimension width, in gfx_dimension height); */ -NS_IMETHODIMP nsImageLoader::LoadImage(nsIURI *aURI, nsIImageRequest **_retval) +/* nsIImageRequest loadImage (in nsIURI uri, in nsIImageDecoderObserver aObserver, in nsISupports cx); */ +NS_IMETHODIMP nsImageLoader::LoadImage(nsIURI *aURI, nsIImageDecoderObserver *aObserver, nsISupports *cx, nsIImageRequest **_retval) { + NS_ASSERTION(aURI, "nsImageLoader::LoadImage -- NULL URI pointer"); -#ifdef IMAGE_THREADPOOL - if (!mThreadPool) { - NS_NewThreadPool(getter_AddRefs(mThreadPool), - 1, 4, - 512, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD); + nsImageRequest *imgRequest = nsnull; + + ImageCache::Get(aURI, &imgRequest); // addrefs + if (!imgRequest) { +#ifdef LOADER_THREADSAFE + nsAutoLock lock(mLock); // lock when we are adding things to the cache +#endif + nsCOMPtr ioserv(do_GetService("@mozilla.org/network/io-service;1")); + if (!ioserv) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 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 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 - nsCOMPtr ioserv(do_GetService("@mozilla.org/network/io-service;1")); - if (!ioserv) return NS_ERROR_FAILURE; + nsCOMPtr req(do_CreateInstance(kImageRequestCID)); - nsCOMPtr newChannel; - ioserv->NewChannelFromURI(aURI, getter_AddRefs(newChannel)); - if (!newChannel) return NS_ERROR_FAILURE; + imgRequest = NS_REINTERPRET_CAST(nsImageRequest*, req.get()); + NS_ADDREF(imgRequest); - newChannel->SetOwner(this); // the channel is now holding a strong ref to 'this' + imgRequest->Init(channel); - // XXX look at the progid - nsCOMPtr imgRequest(do_CreateInstance("@mozilla.org/image/request;1")); - imgRequest->Init(newChannel); + ImageCache::Put(uri, imgRequest); -#ifdef IMAGE_THREADPOOL - nsCOMPtr run(do_QueryInterface(imgRequest)); - mThreadPool->DispatchRequest(run); -#else - nsCOMPtr streamList(do_QueryInterface(imgRequest)); - newChannel->AsyncRead(streamList, nsnull); -#endif + *listener = NS_STATIC_CAST(nsIStreamListener*, imgRequest); + NS_IF_ADDREF(*listener); + } - *_retval = imgRequest; + nsCOMPtr 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; diff --git a/modules/libpr0n/src/nsImageLoader.h b/modules/libpr0n/src/nsImageLoader.h index abaa36cebb81..77a43b129332 100644 --- a/modules/libpr0n/src/nsImageLoader.h +++ b/modules/libpr0n/src/nsImageLoader.h @@ -21,9 +21,13 @@ * Stuart Parmenter */ +//#define LOADER_THREADSAFE 1 + #include "nsIImageLoader.h" -#include "nsIThreadPool.h" -#include "nsCOMPtr.h" + +#ifdef LOADER_THREADSAFE +#include "prlock.h" +#endif #define NS_IMAGELOADER_CID \ { /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \ @@ -43,5 +47,7 @@ public: virtual ~nsImageLoader(); private: - nsCOMPtr mThreadPool; +#ifdef LOADER_THREADSAFE + PRLock *mLock; +#endif }; diff --git a/modules/libpr0n/src/nsImageRequest.cpp b/modules/libpr0n/src/nsImageRequest.cpp index 7048a53346ee..ae2aebacbafd 100644 --- a/modules/libpr0n/src/nsImageRequest.cpp +++ b/modules/libpr0n/src/nsImageRequest.cpp @@ -35,18 +35,18 @@ #include "nsString.h" -#include "nsIEventQueueService.h" -#include "nsIEventQueue.h" +#include "ImageCache.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(); /* member initializers and constructor code */ - mProcessing = PR_TRUE; } nsImageRequest::~nsImageRequest() @@ -55,12 +55,12 @@ nsImageRequest::~nsImageRequest() } - -/* void init (in nsIChannel aChannel, in gfx_dimension width, in gfx_dimension height); */ -NS_IMETHODIMP nsImageRequest::Init(nsIChannel *aChannel) +nsresult nsImageRequest::Init(nsIChannel *aChannel) { - if (mImage) - return NS_ERROR_FAILURE; // XXX + // XXX we should save off the thread we are getting called on here so that we can proxy all calls to mDecoder to it. + + NS_ASSERTION(!mImage, "nsImageRequest::Init -- Multiple calls to init"); + NS_ASSERTION(aChannel, "nsImageRequest::Init -- No channel"); mChannel = aChannel; @@ -70,6 +70,52 @@ NS_IMETHODIMP nsImageRequest::Init(nsIChannel *aChannel) 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; */ NS_IMETHODIMP nsImageRequest::GetImage(nsIImageContainer * *aImage) { @@ -78,113 +124,142 @@ NS_IMETHODIMP nsImageRequest::GetImage(nsIImageContainer * *aImage) return NS_OK; } - - - -/** nsIRequest methods **/ - -/* readonly attribute wstring name; */ -NS_IMETHODIMP nsImageRequest::GetName(PRUnichar * *aName) +/* readonly attribute unsigned long imageStatus; */ +NS_IMETHODIMP nsImageRequest::GetImageStatus(PRUint32 *aStatus) { - return mChannel->GetName(aName); -} - -/* 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(); + *aStatus = mStatus; + return NS_OK; } +/** 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 **/ -/* void onStartDecode (in nsIImageRequest request); */ -NS_IMETHODIMP nsImageRequest::OnStartDecode(nsIImageRequest *request) +/* void onStartDecode (in nsIImageRequest request, in nsISupports cx); */ +NS_IMETHODIMP nsImageRequest::OnStartDecode(nsIImageRequest *request, nsISupports *cx) { - if (mObserver) - mObserver->OnStartDecode(this); + mState |= onStartDecode; + + 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; } -/* void onStartContainer (in nsIImageRequest request, in nsIImageContainer image); */ -NS_IMETHODIMP nsImageRequest::OnStartContainer(nsIImageRequest *request, nsIImageContainer *image) +/* void onStartContainer (in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image); */ +NS_IMETHODIMP nsImageRequest::OnStartContainer(nsIImageRequest *request, nsISupports *cx, nsIImageContainer *image) { - if (mObserver) - mObserver->OnStartContainer(this, image); + mState |= onStartContainer; + + 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; } -/* void onStartFrame (in nsIImageRequest request, in nsIImageFrame frame); */ -NS_IMETHODIMP nsImageRequest::OnStartFrame(nsIImageRequest *request, nsIImageFrame *frame) +/* void onStartFrame (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame); */ +NS_IMETHODIMP nsImageRequest::OnStartFrame(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame) { - if (mObserver) - mObserver->OnStartFrame(this, frame); + PRInt32 i = -1; + 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; } -/* [noscript] void onDataAvailable (in nsIImageRequest request, in nsIImageFrame frame, [const] in nsRect2 rect); */ -NS_IMETHODIMP nsImageRequest::OnDataAvailable(nsIImageRequest *request, nsIImageFrame *frame, const nsRect2 * rect) +/* [noscript] void onDataAvailable (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame, [const] in nsRect rect); */ +NS_IMETHODIMP nsImageRequest::OnDataAvailable(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame, const nsRect * rect) { - if (mObserver) - mObserver->OnDataAvailable(this, frame, rect); + PRInt32 i = -1; + 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; } -/* void onStopFrame (in nsIImageRequest request, in nsIImageFrame frame); */ -NS_IMETHODIMP nsImageRequest::OnStopFrame(nsIImageRequest *request, nsIImageFrame *frame) +/* void onStopFrame (in nsIImageRequest request, in nsISupports cx, in nsIImageFrame frame); */ +NS_IMETHODIMP nsImageRequest::OnStopFrame(nsIImageRequest *request, nsISupports *cx, nsIImageFrame *frame) { - if (mObserver) - mObserver->OnStopFrame(this, frame); + PRInt32 i = -1; + 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; } -/* void onStopContainer (in nsIImageRequest request, in nsIImageContainer image); */ -NS_IMETHODIMP nsImageRequest::OnStopContainer(nsIImageRequest *request, nsIImageContainer *image) +/* void onStopContainer (in nsIImageRequest request, in nsISupports cx, in nsIImageContainer image); */ +NS_IMETHODIMP nsImageRequest::OnStopContainer(nsIImageRequest *request, nsISupports *cx, nsIImageContainer *image) { - if (mObserver) - mObserver->OnStopContainer(this, image); + mState |= onStopContainer; + + + 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; } -/* void onStopDecode (in nsIImageRequest request, in nsresult status, in wstring statusArg); */ -NS_IMETHODIMP nsImageRequest::OnStopDecode(nsIImageRequest *request, nsresult status, const PRUnichar *statusArg) +/* void onStopDecode (in nsIImageRequest request, in nsISupports cx, in nsresult status, in wstring statusArg); */ +NS_IMETHODIMP nsImageRequest::OnStopDecode(nsIImageRequest *request, nsISupports *cx, nsresult status, const PRUnichar *statusArg) { - if (mObserver) - mObserver->OnStopDecode(this, status, statusArg); + mState |= onStopDecode; + + 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; } @@ -199,13 +274,14 @@ NS_IMETHODIMP nsImageRequest::OnStopDecode(nsIImageRequest *request, nsresult st /* void onStartRequest (in nsIChannel channel, in nsISupports ctxt); */ NS_IMETHODIMP nsImageRequest::OnStartRequest(nsIChannel *channel, nsISupports *ctxt) { + NS_ASSERTION(!mDecoder, "nsImageRequest::OnStartRequest -- we already have a decoder"); + nsXPIDLCString contentType; channel->GetContentType(getter_Copies(contentType)); 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 += ";1"; 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); */ 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; + // if we failed, we should remove ourself from the cache + if (NS_FAILED(status)) { + nsCOMPtr uri; + channel->GetURI(getter_AddRefs(uri)); + ImageCache::Remove(uri); + } + + mChannel = nsnull; // we no longer need the channel + 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); */ 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; 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 service = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = service->CreateThreadEventQueue(); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr 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; -} - - - - diff --git a/modules/libpr0n/src/nsImageRequest.h b/modules/libpr0n/src/nsImageRequest.h index 726e9c5c6a10..e6183b37361b 100644 --- a/modules/libpr0n/src/nsImageRequest.h +++ b/modules/libpr0n/src/nsImageRequest.h @@ -21,7 +21,10 @@ * Stuart Parmenter */ -#include "nsIImageRequest.h" +#ifndef nsImageRequest_h__ +#define nsImageRequest_h__ + +#include "nsIImageRequest2.h" #include "nsIRunnable.h" @@ -32,6 +35,8 @@ #include "nsIStreamListener.h" #include "nsCOMPtr.h" +#include "nsVoidArray.h" + #define NS_IMAGEREQUEST_CID \ { /* 9f733dd6-1dd1-11b2-8cdf-effb70d1ea71 */ \ 0x9f733dd6, \ @@ -40,28 +45,44 @@ {0x8c, 0xdf, 0xef, 0xfb, 0x70, 0xd1, 0xea, 0x71} \ } + +enum { + onStartDecode = 0x1, + onStartContainer = 0x2, + onStopContainer = 0x4, + onStopDecode = 0x8 +}; + class nsImageRequest : public nsIImageRequest, public nsIImageDecoderObserver, - public nsIStreamListener, public nsIRunnable + public nsIStreamListener { public: - NS_DECL_ISUPPORTS - NS_DECL_NSIIMAGEREQUEST - NS_DECL_NSIIMAGEDECODEROBSERVER - NS_DECL_NSIREQUEST - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSISTREAMOBSERVER - NS_DECL_NSIRUNNABLE - nsImageRequest(); virtual ~nsImageRequest(); + /* 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: nsCOMPtr mChannel; nsCOMPtr mImage; nsCOMPtr mDecoder; - nsCOMPtr mObserver; + + nsVoidArray mObservers; PRBool mProcessing; + PRUint32 mStatus; + PRUint32 mState; }; + +#endif diff --git a/modules/libpr0n/src/nsImageRequestProxy.cpp b/modules/libpr0n/src/nsImageRequestProxy.cpp new file mode 100644 index 000000000000..a2d7ef6d6028 --- /dev/null +++ b/modules/libpr0n/src/nsImageRequestProxy.cpp @@ -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 + */ + +#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; +} + diff --git a/modules/libpr0n/src/nsImageRequestProxy.h b/modules/libpr0n/src/nsImageRequestProxy.h new file mode 100644 index 000000000000..ec504a5e00b1 --- /dev/null +++ b/modules/libpr0n/src/nsImageRequestProxy.h @@ -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 + */ + +#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 mObserver; + + nsCOMPtr mContext; + + nsCOMPtr mOwner; +};