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
DIRS = ppm png
DIRS = ppm png gif jpeg
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 "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,26 +199,11 @@ 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);
@ -257,17 +211,13 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
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,38 +260,64 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
row_stride, 1);
}
} else {
return NS_OK;
mState = JPEG_START_DECOMPRESS;
}
/* 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.
*/
case JPEG_START_DECOMPRESS:
/* Step 4: set parameters for decompression */
/* 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;
/* 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;
(void) jpeg_start_decompress(&mInfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
mState = JPEG_DECOMPRESS_PROGRESSIVE;
int status;
case JPEG_DECOMPRESS_PROGRESSIVE:
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
* output image dimensions available, as well as the output colormap
@ -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;
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 {
mBytesToSkip -= newBufLen;
return FALSE; // suspend
src->decoder->mInStream->ReadSegments(DiscardData, NS_STATIC_CAST(void*, jd),
src->decoder->mBytesToSkip, &_retval);
}
src->decoder->mBytesToSkip -= _retval;
src->decoder->mDataLen -= _retval;
}
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;
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 {
/* Still need to skip some more data in the future */
src->bytes_to_skip -= (size_t)new_buflen;
goto suspend;
}
return PR_FALSE;
}
/* 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;
}
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;
}
}
@ -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 */
}

View File

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

View File

@ -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, },
};

View File

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

View File

@ -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>

View File

@ -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,20 +343,43 @@ 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;
}
}
@ -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<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));
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);
}
}

View File

@ -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<nsIImageContainer> mImage;
nsCOMPtr<nsIImageFrame> mFrame;
nsCOMPtr<nsIImageRequest> mRequest;
@ -74,6 +74,9 @@ private:
png_structp mPNG;
png_infop mInfo;
PRUint8 *colorLine, *alphaLine;
PRUint8 *interlacebuf;
PRUint32 ibpr;
};
#endif // nsPNGDecoder_h__

View File

@ -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, },
};

View File

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

View File

@ -20,23 +20,20 @@
* Contributor(s):
* 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 "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<nsIImageContainer> 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));

View File

@ -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<nsIImageFrame> mImage;
nsCOMPtr<nsIImageContainer> mImage;
nsCOMPtr<nsIImageFrame> mFrame;
nsCOMPtr<nsIImageRequest> mRequest;
nsCOMPtr<nsIImageDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
PRUint32 mDataReceived;
PRUint32 mDataWritten;

View File

@ -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, },
};

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 \
nsIImageDecoderObserver.idl \
nsIImageLoader.idl \
nsIImageRequest.idl
nsIImageRequest2.idl
include $(topsrcdir)/config/rules.mk

View File

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

View File

@ -27,9 +27,25 @@
interface nsIImageRequest;
/**
* nsIImageDecoder interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @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.

View File

@ -21,13 +21,17 @@
* Stuart Parmenter <pavlov@netscape.com>
*/
#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);
};

View File

@ -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 <pavlov@netscape.com>
* @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;
};

View File

@ -22,23 +22,42 @@
*/
#include "nsISupports.idl"
#include "nsIRequest.idl"
#include "gfxtypes.idl"
interface nsIChannel;
interface nsIImageContainer;
/**
* nsIImageRequest interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @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;
};

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
IS_COMPONENT = 1
CPPSRCS = nsImageFactory.cpp \
CPPSRCS = ImageCache.cpp \
nsImageFactory.cpp \
nsImageLoader.cpp \
nsImageRequest.cpp
nsImageRequest.cpp \
nsImageRequestProxy.cpp
EXTRA_DSO_LDOPTS = \
$(MOZ_COMPONENT_LIBS) \

View File

@ -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)

View File

@ -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)

View File

@ -23,7 +23,7 @@
#include "nsImageLoader.h"
#include "nsIImageRequest.h"
#include "nsIImageRequest2.h"
#include "nsIServiceManager.h"
@ -33,35 +33,57 @@
#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<nsIIOService> ioserv(do_GetService("@mozilla.org/network/io-service;1"));
if (!ioserv) return NS_ERROR_FAILURE;
@ -69,21 +91,78 @@ NS_IMETHODIMP nsImageLoader::LoadImage(nsIURI *aURI, nsIImageRequest **_retval)
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'
// XXX look at the progid
nsCOMPtr<nsIImageRequest> imgRequest(do_CreateInstance("@mozilla.org/image/request;1"));
nsCOMPtr<nsIImageRequest> req(do_CreateInstance(kImageRequestCID));
imgRequest = NS_REINTERPRET_CAST(nsImageRequest*, req.get());
NS_ADDREF(imgRequest);
imgRequest->Init(newChannel);
#ifdef IMAGE_THREADPOOL
nsCOMPtr<nsIRunnable> run(do_QueryInterface(imgRequest));
mThreadPool->DispatchRequest(run);
#else
nsCOMPtr<nsIStreamListener> streamList(do_QueryInterface(imgRequest));
newChannel->AsyncRead(streamList, nsnull);
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
*_retval = imgRequest;
nsCOMPtr<nsIImageRequest> req(do_CreateInstance(kImageRequestCID));
imgRequest = NS_REINTERPRET_CAST(nsImageRequest*, req.get());
NS_ADDREF(imgRequest);
imgRequest->Init(channel);
ImageCache::Put(uri, imgRequest);
*listener = NS_STATIC_CAST(nsIStreamListener*, imgRequest);
NS_IF_ADDREF(*listener);
}
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;

View File

@ -21,9 +21,13 @@
* Stuart Parmenter <pavlov@netscape.com>
*/
//#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<nsIThreadPool> mThreadPool;
#ifdef LOADER_THREADSAFE
PRLock *mLock;
#endif
};

View File

@ -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<nsIURI> 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<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>
*/
#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<nsIChannel> mChannel;
nsCOMPtr<nsIImageContainer> mImage;
nsCOMPtr<nsIImageDecoder> mDecoder;
nsCOMPtr<nsIImageDecoderObserver> mObserver;
nsVoidArray mObservers;
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;
};