зеркало из https://github.com/mozilla/pjs.git
Bug 435296 - Decode-On-Draw. r=joe,roc,bz,dolske,peterw sr=vlad
This commit is contained in:
Родитель
e65a77e1b7
Коммит
92e80175ef
|
@ -524,7 +524,9 @@ static nsresult
|
||||||
WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
|
WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
|
||||||
{
|
{
|
||||||
nsRefPtr<gfxImageSurface> image;
|
nsRefPtr<gfxImageSurface> image;
|
||||||
nsresult rv = aImage->CopyCurrentFrame(getter_AddRefs(image));
|
nsresult rv = aImage->CopyFrame(imgIContainer::FRAME_FIRST,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(image));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
PRInt32 width = image->Width();
|
PRInt32 width = image->Width();
|
||||||
|
|
|
@ -268,6 +268,14 @@ nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, PRBool aLastPart)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsImageLoadingContent::OnDiscard(imgIRequest *aRequest)
|
||||||
|
{
|
||||||
|
LOOP_OVER_OBSERVERS(OnDiscard(aRequest));
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nsIImageLoadingContent impl
|
* nsIImageLoadingContent impl
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -100,6 +100,12 @@ nsStubImageDecoderObserver::OnStopRequest(imgIRequest *aRequest,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsStubImageDecoderObserver::OnDiscard(imgIRequest *aRequest)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsStubImageDecoderObserver::FrameChanged(imgIContainer *aContainer,
|
nsStubImageDecoderObserver::FrameChanged(imgIContainer *aContainer,
|
||||||
nsIntRect * aDirtyRect)
|
nsIntRect * aDirtyRect)
|
||||||
|
|
|
@ -1329,8 +1329,11 @@ nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image,
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The canvas spec says that createPattern should use the first frame
|
||||||
|
// of animated images
|
||||||
nsLayoutUtils::SurfaceFromElementResult res =
|
nsLayoutUtils::SurfaceFromElementResult res =
|
||||||
nsLayoutUtils::SurfaceFromElement(image, nsLayoutUtils::SFE_WANT_NEW_SURFACE);
|
nsLayoutUtils::SurfaceFromElement(image, nsLayoutUtils::SFE_WANT_FIRST_FRAME |
|
||||||
|
nsLayoutUtils::SFE_WANT_NEW_SURFACE);
|
||||||
if (!res.mSurface)
|
if (!res.mSurface)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
@ -2965,8 +2968,11 @@ nsCanvasRenderingContext2D::DrawImage()
|
||||||
nsRefPtr<gfxPattern> pattern;
|
nsRefPtr<gfxPattern> pattern;
|
||||||
nsRefPtr<gfxPath> path;
|
nsRefPtr<gfxPath> path;
|
||||||
|
|
||||||
|
// The canvas spec says that drawImage should draw the first frame
|
||||||
|
// of animated images
|
||||||
|
PRUint32 sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME;
|
||||||
nsLayoutUtils::SurfaceFromElementResult res =
|
nsLayoutUtils::SurfaceFromElementResult res =
|
||||||
nsLayoutUtils::SurfaceFromElement(imgElt);
|
nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags);
|
||||||
if (!res.mSurface)
|
if (!res.mSurface)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
@ -2974,7 +2980,8 @@ nsCanvasRenderingContext2D::DrawImage()
|
||||||
// On non-CE, force a copy if we're using drawImage with our destination
|
// On non-CE, force a copy if we're using drawImage with our destination
|
||||||
// as a source to work around some Cairo self-copy semantics issues.
|
// as a source to work around some Cairo self-copy semantics issues.
|
||||||
if (res.mSurface == mSurface) {
|
if (res.mSurface == mSurface) {
|
||||||
res = nsLayoutUtils::SurfaceFromElement(imgElt, nsLayoutUtils::SFE_WANT_NEW_SURFACE);
|
sfeFlags |= nsLayoutUtils::SFE_WANT_NEW_SURFACE;
|
||||||
|
res = nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags);
|
||||||
if (!res.mSurface)
|
if (!res.mSurface)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2831,7 +2831,7 @@ function test_2d_drawImage_animated_apng() {
|
||||||
deferTest();
|
deferTest();
|
||||||
setTimeout(wrapFunction(function () {
|
setTimeout(wrapFunction(function () {
|
||||||
ctx108.drawImage(document.getElementById('anim-gr_1.png'), 0, 0);
|
ctx108.drawImage(document.getElementById('anim-gr_1.png'), 0, 0);
|
||||||
todo_isPixel(ctx108, 50,25, 0,255,0,255, 2);
|
isPixel(ctx108, 50,25, 0,255,0,255, 2);
|
||||||
isDone_test_2d_drawImage_animated_apng = true;
|
isDone_test_2d_drawImage_animated_apng = true;
|
||||||
}), 5000);
|
}), 5000);
|
||||||
|
|
||||||
|
@ -2856,7 +2856,7 @@ function test_2d_drawImage_animated_gif() {
|
||||||
deferTest();
|
deferTest();
|
||||||
setTimeout(wrapFunction(function () {
|
setTimeout(wrapFunction(function () {
|
||||||
ctx109.drawImage(document.getElementById('anim-gr_1.gif'), 0, 0);
|
ctx109.drawImage(document.getElementById('anim-gr_1.gif'), 0, 0);
|
||||||
todo_isPixel(ctx109, 50,25, 0,255,0,255, 2);
|
isPixel(ctx109, 50,25, 0,255,0,255, 2);
|
||||||
isDone_test_2d_drawImage_animated_gif = true;
|
isDone_test_2d_drawImage_animated_gif = true;
|
||||||
}), 5000);
|
}), 5000);
|
||||||
|
|
||||||
|
@ -14490,8 +14490,8 @@ setTimeout(function () {
|
||||||
ctx458.fillRect(0, 0, 50, 50);
|
ctx458.fillRect(0, 0, 50, 50);
|
||||||
setTimeout(wrapFunction(function () {
|
setTimeout(wrapFunction(function () {
|
||||||
ctx458.fillRect(50, 0, 50, 50);
|
ctx458.fillRect(50, 0, 50, 50);
|
||||||
todo_isPixel(ctx458, 25,25, 0,255,0,255, 2);
|
isPixel(ctx458, 25,25, 0,255,0,255, 2);
|
||||||
todo_isPixel(ctx458, 75,25, 0,255,0,255, 2);
|
isPixel(ctx458, 75,25, 0,255,0,255, 2);
|
||||||
isDone_test_2d_pattern_animated_gif = true;
|
isDone_test_2d_pattern_animated_gif = true;
|
||||||
}), 2500);
|
}), 2500);
|
||||||
}, 2500);
|
}, 2500);
|
||||||
|
|
|
@ -5393,7 +5393,9 @@ nsSVGFEImageElement::Filter(nsSVGFilterInstance *instance,
|
||||||
|
|
||||||
nsRefPtr<gfxASurface> currentFrame;
|
nsRefPtr<gfxASurface> currentFrame;
|
||||||
if (imageContainer)
|
if (imageContainer)
|
||||||
imageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
|
imageContainer->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_NONE,
|
||||||
|
getter_AddRefs(currentFrame));
|
||||||
|
|
||||||
// We need to wrap the surface in a pattern to have somewhere to set the
|
// We need to wrap the surface in a pattern to have somewhere to set the
|
||||||
// graphics filter.
|
// graphics filter.
|
||||||
|
@ -5482,6 +5484,12 @@ nsSVGFEImageElement::OnStartContainer(imgIRequest *aRequest,
|
||||||
{
|
{
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
nsImageLoadingContent::OnStartContainer(aRequest, aContainer);
|
nsImageLoadingContent::OnStartContainer(aRequest, aContainer);
|
||||||
|
|
||||||
|
// Request a decode
|
||||||
|
NS_ABORT_IF_FALSE(aContainer, "who sent the notification then?");
|
||||||
|
aContainer->RequestDecode();
|
||||||
|
|
||||||
|
// We have a size - invalidate
|
||||||
Invalidate();
|
Invalidate();
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2104,7 +2104,7 @@ DrawBorderImage(nsPresContext* aPresContext,
|
||||||
if (req)
|
if (req)
|
||||||
req->GetImageStatus(&status);
|
req->GetImageStatus(&status);
|
||||||
|
|
||||||
NS_ASSERTION(req && (status & imgIRequest::STATUS_FRAME_COMPLETE),
|
NS_ASSERTION(req && (status & imgIRequest::STATUS_LOAD_COMPLETE),
|
||||||
"no image to draw");
|
"no image to draw");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2300,7 +2300,9 @@ DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nsCOMPtr<imgIContainer> subImage;
|
nsCOMPtr<imgIContainer> subImage;
|
||||||
if (NS_FAILED(aImage->ExtractCurrentFrame(aSrc, getter_AddRefs(subImage))))
|
if (NS_FAILED(aImage->ExtractFrame(imgIContainer::FRAME_CURRENT, aSrc,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(subImage))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gfxPattern::GraphicsFilter graphicsFilter =
|
gfxPattern::GraphicsFilter graphicsFilter =
|
||||||
|
@ -2314,7 +2316,7 @@ DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
|
||||||
aUnitSize.height == aFill.height)) {
|
aUnitSize.height == aFill.height)) {
|
||||||
nsLayoutUtils::DrawSingleImage(&aRenderingContext, subImage,
|
nsLayoutUtils::DrawSingleImage(&aRenderingContext, subImage,
|
||||||
graphicsFilter,
|
graphicsFilter,
|
||||||
aFill, aDirtyRect);
|
aFill, aDirtyRect, imgIContainer::FLAG_NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2359,7 +2361,8 @@ DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsLayoutUtils::DrawImage(&aRenderingContext, subImage, graphicsFilter,
|
nsLayoutUtils::DrawImage(&aRenderingContext, subImage, graphicsFilter,
|
||||||
tile, aFill, tile.TopLeft(), aDirtyRect);
|
tile, aFill, tile.TopLeft(), aDirtyRect,
|
||||||
|
imgIContainer::FLAG_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin table border-collapsing section
|
// Begin table border-collapsing section
|
||||||
|
@ -3086,6 +3089,9 @@ PRBool
|
||||||
ImageRenderer::PrepareImage()
|
ImageRenderer::PrepareImage()
|
||||||
{
|
{
|
||||||
if (mImage.IsEmpty() || !mImage.IsComplete()) {
|
if (mImage.IsEmpty() || !mImage.IsComplete()) {
|
||||||
|
// Make sure the image is actually decoding
|
||||||
|
mImage.RequestDecode();
|
||||||
|
|
||||||
// We can not prepare the image for rendering if it is not fully loaded.
|
// We can not prepare the image for rendering if it is not fully loaded.
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -3115,7 +3121,9 @@ ImageRenderer::PrepareImage()
|
||||||
mImageContainer.swap(srcImage);
|
mImageContainer.swap(srcImage);
|
||||||
} else {
|
} else {
|
||||||
nsCOMPtr<imgIContainer> subImage;
|
nsCOMPtr<imgIContainer> subImage;
|
||||||
nsresult rv = srcImage->ExtractCurrentFrame(actualCropRect,
|
nsresult rv = srcImage->ExtractFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
actualCropRect,
|
||||||
|
imgIContainer::FLAG_NONE,
|
||||||
getter_AddRefs(subImage));
|
getter_AddRefs(subImage));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("The cropped image contains no pixels to draw; "
|
NS_WARNING("The cropped image contains no pixels to draw; "
|
||||||
|
@ -3190,7 +3198,7 @@ ImageRenderer::Draw(nsPresContext* aPresContext,
|
||||||
case eStyleImageType_Image:
|
case eStyleImageType_Image:
|
||||||
nsLayoutUtils::DrawImage(&aRenderingContext, mImageContainer,
|
nsLayoutUtils::DrawImage(&aRenderingContext, mImageContainer,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame),
|
nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame),
|
||||||
aDest, aFill, aAnchor, aDirty);
|
aDest, aFill, aAnchor, aDirty, imgIContainer::FLAG_NONE);
|
||||||
break;
|
break;
|
||||||
case eStyleImageType_Gradient:
|
case eStyleImageType_Gradient:
|
||||||
nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
|
nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
|
||||||
|
|
|
@ -73,7 +73,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||||
mIsAtRootOfPseudoStackingContext(PR_FALSE),
|
mIsAtRootOfPseudoStackingContext(PR_FALSE),
|
||||||
mPaintAllFrames(PR_FALSE),
|
mPaintAllFrames(PR_FALSE),
|
||||||
mAccurateVisibleRegions(PR_FALSE),
|
mAccurateVisibleRegions(PR_FALSE),
|
||||||
mInTransform(PR_FALSE) {
|
mInTransform(PR_FALSE),
|
||||||
|
mSyncDecodeImages(PR_FALSE) {
|
||||||
PL_InitArenaPool(&mPool, "displayListArena", 1024, sizeof(void*)-1);
|
PL_InitArenaPool(&mPool, "displayListArena", 1024, sizeof(void*)-1);
|
||||||
|
|
||||||
nsPresContext* pc = aReferenceFrame->PresContext();
|
nsPresContext* pc = aReferenceFrame->PresContext();
|
||||||
|
|
|
@ -290,6 +290,20 @@ public:
|
||||||
*/
|
*/
|
||||||
void SetInTransform(PRBool aInTransform) { mInTransform = aInTransform; }
|
void SetInTransform(PRBool aInTransform) { mInTransform = aInTransform; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PR_TRUE if images have been set to decode synchronously.
|
||||||
|
*/
|
||||||
|
PRBool ShouldSyncDecodeImages() { return mSyncDecodeImages; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether we should synchronously decode images. If true, we decode
|
||||||
|
* and draw whatever image data has been loaded. If false, we just draw
|
||||||
|
* whatever has already been decoded.
|
||||||
|
*/
|
||||||
|
void SetSyncDecodeImages(PRBool aSyncDecodeImages) {
|
||||||
|
mSyncDecodeImages = aSyncDecodeImages;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtracts aRegion from *aVisibleRegion. We avoid letting
|
* Subtracts aRegion from *aVisibleRegion. We avoid letting
|
||||||
* aVisibleRegion become overcomplex by simplifying it if necessary ---
|
* aVisibleRegion become overcomplex by simplifying it if necessary ---
|
||||||
|
@ -396,6 +410,7 @@ private:
|
||||||
// True when we're building a display list that's directly or indirectly
|
// True when we're building a display list that's directly or indirectly
|
||||||
// under an nsDisplayTransform
|
// under an nsDisplayTransform
|
||||||
PRPackedBool mInTransform;
|
PRPackedBool mInTransform;
|
||||||
|
PRPackedBool mSyncDecodeImages;
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsDisplayItem;
|
class nsDisplayItem;
|
||||||
|
|
|
@ -63,10 +63,10 @@
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
|
NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
|
||||||
|
|
||||||
nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRBool aReflowOnLoad,
|
nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRUint32 aActions,
|
||||||
nsImageLoader *aNextLoader)
|
nsImageLoader *aNextLoader)
|
||||||
: mFrame(aFrame),
|
: mFrame(aFrame),
|
||||||
mReflowOnLoad(aReflowOnLoad),
|
mActions(aActions),
|
||||||
mNextLoader(aNextLoader)
|
mNextLoader(aNextLoader)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -82,10 +82,10 @@ nsImageLoader::~nsImageLoader()
|
||||||
|
|
||||||
/* static */ already_AddRefed<nsImageLoader>
|
/* static */ already_AddRefed<nsImageLoader>
|
||||||
nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
||||||
PRBool aReflowOnLoad, nsImageLoader *aNextLoader)
|
PRUint32 aActions, nsImageLoader *aNextLoader)
|
||||||
{
|
{
|
||||||
nsRefPtr<nsImageLoader> loader =
|
nsRefPtr<nsImageLoader> loader =
|
||||||
new nsImageLoader(aFrame, aReflowOnLoad, aNextLoader);
|
new nsImageLoader(aFrame, aActions, aNextLoader);
|
||||||
|
|
||||||
loader->Load(aRequest);
|
loader->Load(aRequest);
|
||||||
|
|
||||||
|
@ -139,8 +139,8 @@ nsImageLoader::Load(imgIRequest *aImage)
|
||||||
NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
|
NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
|
||||||
imgIContainer *aImage)
|
imgIContainer *aImage)
|
||||||
{
|
{
|
||||||
if (aImage)
|
NS_ABORT_IF_FALSE(aImage, "Who's calling us then?");
|
||||||
{
|
|
||||||
/* Get requested animation policy from the pres context:
|
/* Get requested animation policy from the pres context:
|
||||||
* normal = 0
|
* normal = 0
|
||||||
* one frame = 1
|
* one frame = 1
|
||||||
|
@ -149,7 +149,7 @@ NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
|
||||||
aImage->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
|
aImage->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
|
||||||
// Ensure the animation (if any) is started.
|
// Ensure the animation (if any) is started.
|
||||||
aImage->StartAnimation();
|
aImage->StartAnimation();
|
||||||
}
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,26 +159,39 @@ NS_IMETHODIMP nsImageLoader::OnStopFrame(imgIRequest *aRequest,
|
||||||
if (!mFrame)
|
if (!mFrame)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
#ifdef NS_DEBUG
|
if (!mRequest) {
|
||||||
// Make sure the image request status's STATUS_FRAME_COMPLETE flag has been set to ensure
|
// We're in the middle of a paint anyway
|
||||||
// the image will be painted when invalidated
|
return NS_OK;
|
||||||
if (aRequest) {
|
|
||||||
PRUint32 status = imgIRequest::STATUS_ERROR;
|
|
||||||
nsresult rv = aRequest->GetImageStatus(&status);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
NS_ASSERTION((status & imgIRequest::STATUS_FRAME_COMPLETE), "imgIRequest::STATUS_FRAME_COMPLETE not set");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take requested actions
|
||||||
|
if (mActions & ACTION_REFLOW_ON_DECODE) {
|
||||||
|
DoReflow();
|
||||||
}
|
}
|
||||||
#endif
|
if (mActions & ACTION_REDRAW_ON_DECODE) {
|
||||||
|
DoRedraw(nsnull);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsImageLoader::OnStopRequest(imgIRequest *aRequest,
|
||||||
|
PRBool aLastPart)
|
||||||
|
{
|
||||||
|
if (!mFrame)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
if (!mRequest) {
|
if (!mRequest) {
|
||||||
// We're in the middle of a paint anyway
|
// We're in the middle of a paint anyway
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the background image
|
// Take requested actions
|
||||||
RedrawDirtyFrame(nsnull);
|
if (mActions & ACTION_REFLOW_ON_LOAD) {
|
||||||
return NS_OK;
|
DoReflow();
|
||||||
|
}
|
||||||
|
if (mActions & ACTION_REDRAW_ON_LOAD) {
|
||||||
|
DoRedraw(nsnull);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsImageLoader::FrameChanged(imgIContainer *aContainer,
|
NS_IMETHODIMP nsImageLoader::FrameChanged(imgIContainer *aContainer,
|
||||||
|
@ -194,25 +207,25 @@ NS_IMETHODIMP nsImageLoader::FrameChanged(imgIContainer *aContainer,
|
||||||
|
|
||||||
nsRect r = dirtyRect->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
|
nsRect r = dirtyRect->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
|
||||||
|
|
||||||
RedrawDirtyFrame(&r);
|
DoRedraw(&r);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsImageLoader::RedrawDirtyFrame(const nsRect* aDamageRect)
|
nsImageLoader::DoReflow()
|
||||||
{
|
{
|
||||||
if (mReflowOnLoad) {
|
|
||||||
nsIPresShell *shell = mFrame->PresContext()->GetPresShell();
|
nsIPresShell *shell = mFrame->PresContext()->GetPresShell();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
#endif
|
#endif
|
||||||
shell->FrameNeedsReflow(mFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
shell->FrameNeedsReflow(mFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
||||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not reflow after loading border-image");
|
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not reflow after loading border-image");
|
||||||
// The reflow might not do all the invalidation we need, so continue
|
}
|
||||||
// on with the invalidation codepath.
|
|
||||||
}
|
void
|
||||||
|
nsImageLoader::DoRedraw(const nsRect* aDamageRect)
|
||||||
|
{
|
||||||
// NOTE: It is not sufficient to invalidate only the size of the image:
|
// NOTE: It is not sufficient to invalidate only the size of the image:
|
||||||
// the image may be tiled!
|
// the image may be tiled!
|
||||||
// The best option is to call into the frame, however lacking this
|
// The best option is to call into the frame, however lacking this
|
||||||
|
|
|
@ -57,20 +57,33 @@ class nsIURI;
|
||||||
class nsImageLoader : public nsStubImageDecoderObserver
|
class nsImageLoader : public nsStubImageDecoderObserver
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
nsImageLoader(nsIFrame *aFrame, PRBool aReflowOnLoad,
|
nsImageLoader(nsIFrame *aFrame, PRUint32 aActions,
|
||||||
nsImageLoader *aNextLoader);
|
nsImageLoader *aNextLoader);
|
||||||
virtual ~nsImageLoader();
|
virtual ~nsImageLoader();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/*
|
||||||
|
* Flags to specify actions that can be taken for the image at various
|
||||||
|
* times. Reflows always occur before redraws. "Decode" refers to one
|
||||||
|
* frame being available, whereas "load" refers to all the data being loaded
|
||||||
|
* from the network.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ACTION_REFLOW_ON_DECODE = 0x01,
|
||||||
|
ACTION_REDRAW_ON_DECODE = 0x02,
|
||||||
|
ACTION_REFLOW_ON_LOAD = 0x04,
|
||||||
|
ACTION_REDRAW_ON_LOAD = 0x08
|
||||||
|
};
|
||||||
static already_AddRefed<nsImageLoader>
|
static already_AddRefed<nsImageLoader>
|
||||||
Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
||||||
PRBool aReflowOnLoad, nsImageLoader *aNextLoader);
|
PRUint32 aActions, nsImageLoader *aNextLoader);
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
// imgIDecoderObserver (override nsStubImageDecoderObserver)
|
// imgIDecoderObserver (override nsStubImageDecoderObserver)
|
||||||
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
|
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
|
||||||
NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
|
NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
|
||||||
|
NS_IMETHOD OnStopRequest(imgIRequest *aRequest, PRBool aLastPart);
|
||||||
// Do not override OnDataAvailable since background images are not
|
// Do not override OnDataAvailable since background images are not
|
||||||
// displayed incrementally; they are displayed after the entire image
|
// displayed incrementally; they are displayed after the entire image
|
||||||
// has been loaded.
|
// has been loaded.
|
||||||
|
@ -87,10 +100,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsresult Load(imgIRequest *aImage);
|
nsresult Load(imgIRequest *aImage);
|
||||||
void RedrawDirtyFrame(const nsRect* aDamageRect);
|
void DoReflow();
|
||||||
|
/* if aDamageRect is nsnull, the whole frame is redrawn. */
|
||||||
|
void DoRedraw(const nsRect* aDamageRect);
|
||||||
|
|
||||||
nsIFrame *mFrame;
|
nsIFrame *mFrame;
|
||||||
nsCOMPtr<imgIRequest> mRequest;
|
nsCOMPtr<imgIRequest> mRequest;
|
||||||
PRBool mReflowOnLoad;
|
PRUint32 mActions;
|
||||||
nsRefPtr<nsImageLoader> mNextLoader;
|
nsRefPtr<nsImageLoader> mNextLoader;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1061,6 +1061,9 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra
|
||||||
if (aFlags & PAINT_IN_TRANSFORM) {
|
if (aFlags & PAINT_IN_TRANSFORM) {
|
||||||
builder.SetInTransform(PR_TRUE);
|
builder.SetInTransform(PR_TRUE);
|
||||||
}
|
}
|
||||||
|
if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
|
||||||
|
builder.SetSyncDecodeImages(PR_TRUE);
|
||||||
|
}
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
builder.EnterPresShell(aFrame, dirtyRect);
|
builder.EnterPresShell(aFrame, dirtyRect);
|
||||||
|
@ -2774,7 +2777,8 @@ DrawImageInternal(nsIRenderingContext* aRenderingContext,
|
||||||
const nsRect& aFill,
|
const nsRect& aFill,
|
||||||
const nsPoint& aAnchor,
|
const nsPoint& aAnchor,
|
||||||
const nsRect& aDirty,
|
const nsRect& aDirty,
|
||||||
const nsIntSize& aImageSize)
|
const nsIntSize& aImageSize,
|
||||||
|
PRUint32 aImageFlags)
|
||||||
{
|
{
|
||||||
if (aDest.IsEmpty() || aFill.IsEmpty())
|
if (aDest.IsEmpty() || aFill.IsEmpty())
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2872,7 +2876,8 @@ DrawImageInternal(nsIRenderingContext* aRenderingContext,
|
||||||
if (finalFillRect.IsEmpty())
|
if (finalFillRect.IsEmpty())
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
aImage->Draw(ctx, aGraphicsFilter, transform, finalFillRect, intSubimage);
|
aImage->Draw(ctx, aGraphicsFilter, transform, finalFillRect, intSubimage,
|
||||||
|
aImageFlags);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2881,6 +2886,7 @@ nsLayoutUtils::DrawSingleUnscaledImage(nsIRenderingContext* aRenderingContext,
|
||||||
imgIContainer* aImage,
|
imgIContainer* aImage,
|
||||||
const nsPoint& aDest,
|
const nsPoint& aDest,
|
||||||
const nsRect& aDirty,
|
const nsRect& aDirty,
|
||||||
|
PRUint32 aImageFlags,
|
||||||
const nsRect* aSourceArea)
|
const nsRect* aSourceArea)
|
||||||
{
|
{
|
||||||
nsIntSize imageSize;
|
nsIntSize imageSize;
|
||||||
|
@ -2906,7 +2912,7 @@ nsLayoutUtils::DrawSingleUnscaledImage(nsIRenderingContext* aRenderingContext,
|
||||||
// translation but we don't want to actually tile the image.
|
// translation but we don't want to actually tile the image.
|
||||||
fill.IntersectRect(fill, dest);
|
fill.IntersectRect(fill, dest);
|
||||||
return DrawImageInternal(aRenderingContext, aImage, gfxPattern::FILTER_NEAREST,
|
return DrawImageInternal(aRenderingContext, aImage, gfxPattern::FILTER_NEAREST,
|
||||||
dest, fill, aDest, aDirty, imageSize);
|
dest, fill, aDest, aDirty, imageSize, aImageFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsresult
|
/* static */ nsresult
|
||||||
|
@ -2915,6 +2921,7 @@ nsLayoutUtils::DrawSingleImage(nsIRenderingContext* aRenderingContext,
|
||||||
gfxPattern::GraphicsFilter aGraphicsFilter,
|
gfxPattern::GraphicsFilter aGraphicsFilter,
|
||||||
const nsRect& aDest,
|
const nsRect& aDest,
|
||||||
const nsRect& aDirty,
|
const nsRect& aDirty,
|
||||||
|
PRUint32 aImageFlags,
|
||||||
const nsRect* aSourceArea)
|
const nsRect* aSourceArea)
|
||||||
{
|
{
|
||||||
nsIntSize imageSize;
|
nsIntSize imageSize;
|
||||||
|
@ -2939,7 +2946,7 @@ nsLayoutUtils::DrawSingleImage(nsIRenderingContext* aRenderingContext,
|
||||||
nsRect fill;
|
nsRect fill;
|
||||||
fill.IntersectRect(aDest, dest);
|
fill.IntersectRect(aDest, dest);
|
||||||
return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter, dest, fill,
|
return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter, dest, fill,
|
||||||
fill.TopLeft(), aDirty, imageSize);
|
fill.TopLeft(), aDirty, imageSize, aImageFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsresult
|
/* static */ nsresult
|
||||||
|
@ -2949,7 +2956,8 @@ nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
|
||||||
const nsRect& aDest,
|
const nsRect& aDest,
|
||||||
const nsRect& aFill,
|
const nsRect& aFill,
|
||||||
const nsPoint& aAnchor,
|
const nsPoint& aAnchor,
|
||||||
const nsRect& aDirty)
|
const nsRect& aDirty,
|
||||||
|
PRUint32 aImageFlags)
|
||||||
{
|
{
|
||||||
nsIntSize imageSize;
|
nsIntSize imageSize;
|
||||||
aImage->GetWidth(&imageSize.width);
|
aImage->GetWidth(&imageSize.width);
|
||||||
|
@ -2958,7 +2966,7 @@ nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
|
||||||
|
|
||||||
return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
|
return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
|
||||||
aDest, aFill, aAnchor, aDirty,
|
aDest, aFill, aAnchor, aDirty,
|
||||||
imageSize);
|
imageSize, aImageFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsRect
|
/* static */ nsRect
|
||||||
|
@ -3364,8 +3372,13 @@ nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement,
|
||||||
if (NS_FAILED(rv) || !imgContainer)
|
if (NS_FAILED(rv) || !imgContainer)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
PRUint32 whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME)
|
||||||
|
? (PRUint32) imgIContainer::FRAME_FIRST
|
||||||
|
: (PRUint32) imgIContainer::FRAME_CURRENT;
|
||||||
nsRefPtr<gfxASurface> framesurf;
|
nsRefPtr<gfxASurface> framesurf;
|
||||||
rv = imgContainer->GetCurrentFrame(getter_AddRefs(framesurf));
|
rv = imgContainer->GetFrame(whichFrame,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(framesurf));
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ class nsIFontMetrics;
|
||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "gfxPattern.h"
|
#include "gfxPattern.h"
|
||||||
|
#include "imgIContainer.h"
|
||||||
|
|
||||||
class nsBlockFrame;
|
class nsBlockFrame;
|
||||||
class nsTextFragment;
|
class nsTextFragment;
|
||||||
|
@ -476,7 +477,11 @@ public:
|
||||||
static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor);
|
static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor);
|
||||||
|
|
||||||
|
|
||||||
enum { PAINT_IN_TRANSFORM = 0x01 };
|
enum {
|
||||||
|
PAINT_IN_TRANSFORM = 0x01,
|
||||||
|
PAINT_SYNC_DECODE_IMAGES = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given aFrame, the root frame of a stacking context, paint it and its
|
* Given aFrame, the root frame of a stacking context, paint it and its
|
||||||
* descendants to aRenderingContext.
|
* descendants to aRenderingContext.
|
||||||
|
@ -488,7 +493,8 @@ public:
|
||||||
* @param aBackstop paint the dirty area with this color before drawing
|
* @param aBackstop paint the dirty area with this color before drawing
|
||||||
* the actual content; pass NS_RGBA(0,0,0,0) to draw no background
|
* the actual content; pass NS_RGBA(0,0,0,0) to draw no background
|
||||||
* @param aFlags if PAINT_IN_TRANSFORM is set, then we assume
|
* @param aFlags if PAINT_IN_TRANSFORM is set, then we assume
|
||||||
* this is inside a transform or SVG foreignObject.
|
* this is inside a transform or SVG foreignObject. If
|
||||||
|
* PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all images.
|
||||||
*/
|
*/
|
||||||
static nsresult PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame,
|
static nsresult PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame,
|
||||||
const nsRegion& aDirtyRegion, nscolor aBackstop,
|
const nsRegion& aDirtyRegion, nscolor aBackstop,
|
||||||
|
@ -880,6 +886,7 @@ public:
|
||||||
* @param aAnchor A point in aFill which we will ensure is
|
* @param aAnchor A point in aFill which we will ensure is
|
||||||
* pixel-aligned in the output.
|
* pixel-aligned in the output.
|
||||||
* @param aDirty Pixels outside this area may be skipped.
|
* @param aDirty Pixels outside this area may be skipped.
|
||||||
|
* @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
|
||||||
*/
|
*/
|
||||||
static nsresult DrawImage(nsIRenderingContext* aRenderingContext,
|
static nsresult DrawImage(nsIRenderingContext* aRenderingContext,
|
||||||
imgIContainer* aImage,
|
imgIContainer* aImage,
|
||||||
|
@ -887,7 +894,8 @@ public:
|
||||||
const nsRect& aDest,
|
const nsRect& aDest,
|
||||||
const nsRect& aFill,
|
const nsRect& aFill,
|
||||||
const nsPoint& aAnchor,
|
const nsPoint& aAnchor,
|
||||||
const nsRect& aDirty);
|
const nsRect& aDirty,
|
||||||
|
PRUint32 aImageFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a whole image without scaling or tiling.
|
* Draw a whole image without scaling or tiling.
|
||||||
|
@ -898,6 +906,7 @@ public:
|
||||||
* @param aImage The image.
|
* @param aImage The image.
|
||||||
* @param aDest The top-left where the image should be drawn
|
* @param aDest The top-left where the image should be drawn
|
||||||
* @param aDirty Pixels outside this area may be skipped.
|
* @param aDirty Pixels outside this area may be skipped.
|
||||||
|
* @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
|
||||||
* @param aSourceArea If non-null, this area is extracted from
|
* @param aSourceArea If non-null, this area is extracted from
|
||||||
* the image and drawn at aDest. It's
|
* the image and drawn at aDest. It's
|
||||||
* in appunits. For best results it should
|
* in appunits. For best results it should
|
||||||
|
@ -907,6 +916,7 @@ public:
|
||||||
imgIContainer* aImage,
|
imgIContainer* aImage,
|
||||||
const nsPoint& aDest,
|
const nsPoint& aDest,
|
||||||
const nsRect& aDirty,
|
const nsRect& aDirty,
|
||||||
|
PRUint32 aImageFlags,
|
||||||
const nsRect* aSourceArea = nsnull);
|
const nsRect* aSourceArea = nsnull);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -922,12 +932,14 @@ public:
|
||||||
* the image and drawn in aDest. It's
|
* the image and drawn in aDest. It's
|
||||||
* in appunits. For best results it should
|
* in appunits. For best results it should
|
||||||
* be aligned with image pixels.
|
* be aligned with image pixels.
|
||||||
|
* @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
|
||||||
*/
|
*/
|
||||||
static nsresult DrawSingleImage(nsIRenderingContext* aRenderingContext,
|
static nsresult DrawSingleImage(nsIRenderingContext* aRenderingContext,
|
||||||
imgIContainer* aImage,
|
imgIContainer* aImage,
|
||||||
gfxPattern::GraphicsFilter aGraphicsFilter,
|
gfxPattern::GraphicsFilter aGraphicsFilter,
|
||||||
const nsRect& aDest,
|
const nsRect& aDest,
|
||||||
const nsRect& aDirty,
|
const nsRect& aDirty,
|
||||||
|
PRUint32 aImageFlags,
|
||||||
const nsRect* aSourceArea = nsnull);
|
const nsRect* aSourceArea = nsnull);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1069,7 +1081,10 @@ public:
|
||||||
/* Always create a new surface for the result */
|
/* Always create a new surface for the result */
|
||||||
SFE_WANT_NEW_SURFACE = 1 << 0,
|
SFE_WANT_NEW_SURFACE = 1 << 0,
|
||||||
/* When creating a new surface, create an image surface */
|
/* When creating a new surface, create an image surface */
|
||||||
SFE_WANT_IMAGE_SURFACE = 1 << 1
|
SFE_WANT_IMAGE_SURFACE = 1 << 1,
|
||||||
|
/* Whether to extract the first frame (as opposed to the
|
||||||
|
current frame) in the case that the element is an image. */
|
||||||
|
SFE_WANT_FIRST_FRAME = 1 << 2
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SurfaceFromElementResult {
|
struct SurfaceFromElementResult {
|
||||||
|
|
|
@ -1276,8 +1276,9 @@ nsPresContext::SetupBackgroundImageLoaders(nsIFrame* aFrame,
|
||||||
nsRefPtr<nsImageLoader> loaders;
|
nsRefPtr<nsImageLoader> loaders;
|
||||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, aStyleBackground) {
|
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, aStyleBackground) {
|
||||||
if (aStyleBackground->mLayers[i].mImage.GetType() == eStyleImageType_Image) {
|
if (aStyleBackground->mLayers[i].mImage.GetType() == eStyleImageType_Image) {
|
||||||
|
PRUint32 actions = nsImageLoader::ACTION_REDRAW_ON_DECODE;
|
||||||
imgIRequest *image = aStyleBackground->mLayers[i].mImage.GetImageData();
|
imgIRequest *image = aStyleBackground->mLayers[i].mImage.GetImageData();
|
||||||
loaders = nsImageLoader::Create(aFrame, image, PR_FALSE, loaders);
|
loaders = nsImageLoader::Create(aFrame, image, actions, loaders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetImageLoaders(aFrame, BACKGROUND_IMAGE, loaders);
|
SetImageLoaders(aFrame, BACKGROUND_IMAGE, loaders);
|
||||||
|
@ -1287,9 +1288,12 @@ void
|
||||||
nsPresContext::SetupBorderImageLoaders(nsIFrame* aFrame,
|
nsPresContext::SetupBorderImageLoaders(nsIFrame* aFrame,
|
||||||
const nsStyleBorder* aStyleBorder)
|
const nsStyleBorder* aStyleBorder)
|
||||||
{
|
{
|
||||||
|
PRUint32 actions = nsImageLoader::ACTION_REDRAW_ON_LOAD;
|
||||||
|
if (aStyleBorder->ImageBorderDiffers())
|
||||||
|
actions |= nsImageLoader::ACTION_REFLOW_ON_LOAD;
|
||||||
nsRefPtr<nsImageLoader> loader =
|
nsRefPtr<nsImageLoader> loader =
|
||||||
nsImageLoader::Create(aFrame, aStyleBorder->GetBorderImage(),
|
nsImageLoader::Create(aFrame, aStyleBorder->GetBorderImage(),
|
||||||
aStyleBorder->ImageBorderDiffers(), nsnull);
|
actions, nsnull);
|
||||||
SetImageLoaders(aFrame, BORDER_IMAGE, loader);
|
SetImageLoaders(aFrame, BORDER_IMAGE, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5182,6 +5182,7 @@ PresShell::RenderDocument(const nsRect& aRect, PRUint32 aFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.SetBackgroundOnly(PR_FALSE);
|
builder.SetBackgroundOnly(PR_FALSE);
|
||||||
|
builder.SetSyncDecodeImages(PR_TRUE);
|
||||||
builder.EnterPresShell(rootFrame, rect);
|
builder.EnterPresShell(rootFrame, rect);
|
||||||
|
|
||||||
// Add the canvas background color.
|
// Add the canvas background color.
|
||||||
|
|
|
@ -7,16 +7,24 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=445810
|
||||||
<title>Test for Bug 445810</title>
|
<title>Test for Bug 445810</title>
|
||||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/modules/libpr0n/test/mochitest/imgutils.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=445810">Mozilla Bug 445810</a>
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=445810">Mozilla Bug 445810</a>
|
||||||
<div><p id="display"></p></div>
|
<div><p id="display"></p></div>
|
||||||
|
<div style="display: none;"><img id="currimg"></div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
/** Test for Bug 445810 **/
|
/** Test for Bug 445810 **/
|
||||||
|
|
||||||
|
// Once the border image is loaded, it isn't necessarily decoded. We need to
|
||||||
|
// force a decode, but only have a good way of doing that for image elements,
|
||||||
|
// not border images. However, we can take advantage of the image cache (which
|
||||||
|
// shares images of the same url) and assign the same url to both.
|
||||||
|
var currImageElem = document.getElementById("currimg");
|
||||||
|
|
||||||
function new_image_url()
|
function new_image_url()
|
||||||
{
|
{
|
||||||
var width = 10;
|
var width = 10;
|
||||||
|
@ -60,12 +68,20 @@ is(divcs.width, "11px", // 3 (border-left) + 5 (width) + 3 (border-right)
|
||||||
is(divcs.height, "11px", // 3 (border-top) + 5 (height) + 3 (border-bottom)
|
is(divcs.height, "11px", // 3 (border-top) + 5 (height) + 3 (border-bottom)
|
||||||
"correct height without a border image");
|
"correct height without a border image");
|
||||||
|
|
||||||
p.style.MozBorderImage = "url( " + new_image_url() + ") 2 2 2 2 / 7px 2px";
|
currImageElem.src = new_image_url();
|
||||||
|
p.style.MozBorderImage = "url( " + currImageElem.src + ") 2 2 2 2 / 7px 2px";
|
||||||
is(divcs.width, "11px", "border image not loaded yet");
|
is(divcs.width, "11px", "border image not loaded yet");
|
||||||
is(divcs.height, "11px", "border image not loaded yet");
|
is(divcs.height, "11px", "border image not loaded yet");
|
||||||
|
currImageElem.onload = step2;
|
||||||
|
|
||||||
setTimeout(step2, 0);
|
|
||||||
function step2() {
|
function step2() {
|
||||||
|
// We got here through onload
|
||||||
|
ok(isImageLoaded("currimg"), "image loaded");
|
||||||
|
|
||||||
|
// Force a decode
|
||||||
|
forceDecode("currimg");
|
||||||
|
ok(isFrameDecoded("currimg"), "frame decoded");
|
||||||
|
|
||||||
is(divcs.width, "9px", "border image loading caused reflow");
|
is(divcs.width, "9px", "border image loading caused reflow");
|
||||||
is(divcs.height, "19px", "border image loading caused reflow");
|
is(divcs.height, "19px", "border image loading caused reflow");
|
||||||
|
|
||||||
|
@ -77,24 +93,40 @@ function step2() {
|
||||||
is(divcs.width, "5px", "correct width without a border");
|
is(divcs.width, "5px", "correct width without a border");
|
||||||
is(divcs.height, "5px", "correct height without a border");
|
is(divcs.height, "5px", "correct height without a border");
|
||||||
|
|
||||||
p.style.MozBorderImage = "url( " + new_image_url() + ") 2 2 2 2 / 7px 2px";
|
currImageElem.src = new_image_url();
|
||||||
|
p.style.MozBorderImage = "url( " + currImageElem.src + ") 2 2 2 2 / 7px 2px";
|
||||||
is(divcs.width, "5px", "border image not loaded yet");
|
is(divcs.width, "5px", "border image not loaded yet");
|
||||||
is(divcs.height, "5px", "border image not loaded yet");
|
is(divcs.height, "5px", "border image not loaded yet");
|
||||||
setTimeout(step3, 0);
|
currImageElem.onload = step3;
|
||||||
}
|
}
|
||||||
|
|
||||||
function step3() {
|
function step3() {
|
||||||
|
// We got here through onload
|
||||||
|
ok(isImageLoaded("currimg"), "image loaded");
|
||||||
|
|
||||||
|
// Force a decode
|
||||||
|
forceDecode("currimg");
|
||||||
|
ok(isFrameDecoded("currimg"), "frame decoded");
|
||||||
|
|
||||||
is(divcs.width, "9px", "border image loading caused reflow");
|
is(divcs.width, "9px", "border image loading caused reflow");
|
||||||
is(divcs.height, "19px", "border image loading caused reflow");
|
is(divcs.height, "19px", "border image loading caused reflow");
|
||||||
|
|
||||||
p.style.MozBorderImage = "url( " + new_image_url() + ") 2 2 2 2";
|
currImageElem.src = new_image_url();
|
||||||
|
p.style.MozBorderImage = "url( " + currImageElem.src + ") 2 2 2 2";
|
||||||
p.style.border = "3px none";
|
p.style.border = "3px none";
|
||||||
is(divcs.width, "5px", "border image not loaded yet");
|
is(divcs.width, "5px", "border image not loaded yet");
|
||||||
is(divcs.height, "5px", "border image not loaded yet");
|
is(divcs.height, "5px", "border image not loaded yet");
|
||||||
setTimeout(step4, 0);
|
currImageElem.onload = step4;
|
||||||
}
|
}
|
||||||
|
|
||||||
function step4() {
|
function step4() {
|
||||||
|
// We got here through onload
|
||||||
|
ok(isImageLoaded("currimg"), "image loaded");
|
||||||
|
|
||||||
|
// Force a decode
|
||||||
|
forceDecode("currimg");
|
||||||
|
ok(isFrameDecoded("currimg"), "frame decoded");
|
||||||
|
|
||||||
is(divcs.width, "11px", "border image loading caused reflow");
|
is(divcs.width, "11px", "border image loading caused reflow");
|
||||||
is(divcs.height, "11px", "border image loading caused reflow");
|
is(divcs.height, "11px", "border image loading caused reflow");
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,7 @@ nsBulletFrame::PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt,
|
||||||
mRect.height - (mPadding.top + mPadding.bottom));
|
mRect.height - (mPadding.top + mPadding.bottom));
|
||||||
nsLayoutUtils::DrawSingleImage(&aRenderingContext,
|
nsLayoutUtils::DrawSingleImage(&aRenderingContext,
|
||||||
imageCon, nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
imageCon, nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
||||||
dest + aPt, aDirtyRect);
|
dest + aPt, aDirtyRect, imgIContainer::FLAG_NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6095,7 +6095,7 @@ void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
|
||||||
item < item_end; ++item) {
|
item < item_end; ++item) {
|
||||||
PRUint32 status;
|
PRUint32 status;
|
||||||
nsresult rv = item->mImage->GetImageStatus(&status);
|
nsresult rv = item->mImage->GetImageStatus(&status);
|
||||||
if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_FRAME_COMPLETE)) {
|
if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
|
||||||
// This is the one we want
|
// This is the one we want
|
||||||
item->mImage->GetImage(getter_AddRefs(aCursor.mContainer));
|
item->mImage->GetImage(getter_AddRefs(aCursor.mContainer));
|
||||||
aCursor.mHaveHotspot = item->mHaveHotspot;
|
aCursor.mHaveHotspot = item->mHaveHotspot;
|
||||||
|
|
|
@ -1050,7 +1050,8 @@ nsImageFrame::DisplayAltFeedback(nsIRenderingContext& aRenderingContext,
|
||||||
inner.XMost() - size : inner.x,
|
inner.XMost() - size : inner.x,
|
||||||
inner.y, size, size);
|
inner.y, size, size);
|
||||||
nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
|
nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect);
|
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
|
||||||
|
imgIContainer::FLAG_NONE);
|
||||||
iconUsed = PR_TRUE;
|
iconUsed = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,12 +1145,16 @@ void
|
||||||
nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder,
|
nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder,
|
||||||
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
|
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
|
||||||
static_cast<nsImageFrame*>(mFrame)->
|
static_cast<nsImageFrame*>(mFrame)->
|
||||||
PaintImage(*aCtx, aBuilder->ToReferenceFrame(mFrame), aDirtyRect, mImage);
|
PaintImage(*aCtx, aBuilder->ToReferenceFrame(mFrame), aDirtyRect, mImage,
|
||||||
|
aBuilder->ShouldSyncDecodeImages()
|
||||||
|
? (PRUint32) imgIContainer::FLAG_SYNC_DECODE
|
||||||
|
: (PRUint32) imgIContainer::FLAG_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsImageFrame::PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
|
nsImageFrame::PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
|
||||||
const nsRect& aDirtyRect, imgIContainer* aImage)
|
const nsRect& aDirtyRect, imgIContainer* aImage,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
// Render the image into our content area (the area inside
|
// Render the image into our content area (the area inside
|
||||||
// the borders and padding)
|
// the borders and padding)
|
||||||
|
@ -1159,7 +1164,8 @@ nsImageFrame::PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
|
||||||
dest.y -= GetContinuationOffset();
|
dest.y -= GetContinuationOffset();
|
||||||
|
|
||||||
nsLayoutUtils::DrawSingleImage(&aRenderingContext, aImage,
|
nsLayoutUtils::DrawSingleImage(&aRenderingContext, aImage,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect);
|
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
|
||||||
|
aFlags);
|
||||||
|
|
||||||
nsPresContext* presContext = PresContext();
|
nsPresContext* presContext = PresContext();
|
||||||
nsImageMap* map = GetImageMap(presContext);
|
nsImageMap* map = GetImageMap(presContext);
|
||||||
|
@ -1848,6 +1854,12 @@ nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsImageFrame::IconLoad::OnDiscard(imgIRequest *aRequest)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsImageFrame::IconLoad::FrameChanged(imgIContainer *aContainer,
|
nsImageFrame::IconLoad::FrameChanged(imgIContainer *aContainer,
|
||||||
nsIntRect * aDirtyRect)
|
nsIntRect * aDirtyRect)
|
||||||
|
|
|
@ -215,7 +215,8 @@ protected:
|
||||||
const nsRect& aRect);
|
const nsRect& aRect);
|
||||||
|
|
||||||
void PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
|
void PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
|
||||||
const nsRect& aDirtyRect, imgIContainer* aImage);
|
const nsRect& aDirtyRect, imgIContainer* aImage,
|
||||||
|
PRUint32 aFlags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class nsImageListener;
|
friend class nsImageListener;
|
||||||
|
|
|
@ -581,7 +581,8 @@ nsPageFrame::PaintPageContent(nsIRenderingContext& aRenderingContext,
|
||||||
rect, backgroundRect, 0);
|
rect, backgroundRect, 0);
|
||||||
|
|
||||||
nsLayoutUtils::PaintFrame(&aRenderingContext, pageContentFrame,
|
nsLayoutUtils::PaintFrame(&aRenderingContext, pageContentFrame,
|
||||||
nsRegion(rect), NS_RGBA(0,0,0,0));
|
nsRegion(rect), NS_RGBA(0,0,0,0),
|
||||||
|
nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
|
||||||
|
|
||||||
aRenderingContext.PopState();
|
aRenderingContext.PopState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -639,7 +639,8 @@ nsSimplePageSequenceFrame::PrintNextPage()
|
||||||
mCurrentPageFrame->GetSize());
|
mCurrentPageFrame->GetSize());
|
||||||
nsRegion drawingRegion(drawingRect);
|
nsRegion drawingRegion(drawingRect);
|
||||||
nsLayoutUtils::PaintFrame(renderingContext, mCurrentPageFrame,
|
nsLayoutUtils::PaintFrame(renderingContext, mCurrentPageFrame,
|
||||||
drawingRegion, NS_RGBA(0,0,0,0));
|
drawingRegion, NS_RGBA(0,0,0,0),
|
||||||
|
nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
|
||||||
|
|
||||||
if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) {
|
if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) {
|
||||||
selectionY += height;
|
selectionY += height;
|
||||||
|
@ -707,7 +708,8 @@ nsSimplePageSequenceFrame::PaintPageSequence(nsIRenderingContext& aRenderingCont
|
||||||
aRenderingContext.PushState();
|
aRenderingContext.PushState();
|
||||||
aRenderingContext.Translate(pt.x, pt.y);
|
aRenderingContext.Translate(pt.x, pt.y);
|
||||||
nsLayoutUtils::PaintFrame(&aRenderingContext, child,
|
nsLayoutUtils::PaintFrame(&aRenderingContext, child,
|
||||||
nsRegion(rect - pt), NS_RGBA(0,0,0,0));
|
nsRegion(rect - pt), NS_RGBA(0,0,0,0),
|
||||||
|
nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
|
||||||
aRenderingContext.PopState();
|
aRenderingContext.PopState();
|
||||||
child = child->GetNextSibling();
|
child = child->GetNextSibling();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1472,6 +1472,14 @@ nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsStyleImage::RequestDecode()
|
||||||
|
{
|
||||||
|
if ((mType == eStyleImageType_Image) && mImage)
|
||||||
|
return mImage->RequestDecode();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
nsStyleImage::IsOpaque() const
|
nsStyleImage::IsOpaque() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -250,6 +250,10 @@ struct nsStyleImage {
|
||||||
PRBool ComputeActualCropRect(nsIntRect& aActualCropRect,
|
PRBool ComputeActualCropRect(nsIntRect& aActualCropRect,
|
||||||
PRBool* aIsEntireImage = nsnull) const;
|
PRBool* aIsEntireImage = nsnull) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a decode on the image.
|
||||||
|
*/
|
||||||
|
nsresult RequestDecode();
|
||||||
/**
|
/**
|
||||||
* @return PR_TRUE if the item is definitely opaque --- i.e., paints every
|
* @return PR_TRUE if the item is definitely opaque --- i.e., paints every
|
||||||
* pixel within its bounds opaquely, and the bounds contains at least a pixel.
|
* pixel within its bounds opaquely, and the bounds contains at least a pixel.
|
||||||
|
@ -785,6 +789,7 @@ struct nsStyleBorder {
|
||||||
|
|
||||||
// Defined in nsStyleStructInlines.h
|
// Defined in nsStyleStructInlines.h
|
||||||
inline PRBool IsBorderImageLoaded() const;
|
inline PRBool IsBorderImageLoaded() const;
|
||||||
|
inline nsresult RequestDecode();
|
||||||
|
|
||||||
void GetBorderColor(PRUint8 aSide, nscolor& aColor,
|
void GetBorderColor(PRUint8 aSide, nscolor& aColor,
|
||||||
PRBool& aForeground) const
|
PRBool& aForeground) const
|
||||||
|
|
|
@ -51,6 +51,15 @@ inline void
|
||||||
nsStyleBorder::SetBorderImage(imgIRequest* aImage)
|
nsStyleBorder::SetBorderImage(imgIRequest* aImage)
|
||||||
{
|
{
|
||||||
mBorderImage = aImage;
|
mBorderImage = aImage;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request a decode to jump start decoding, and lock it to make sure it
|
||||||
|
* stays decoded.
|
||||||
|
*/
|
||||||
|
if (mBorderImage) {
|
||||||
|
mBorderImage->RequestDecode();
|
||||||
|
mBorderImage->LockImage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline imgIRequest*
|
inline imgIRequest*
|
||||||
|
@ -64,7 +73,7 @@ inline PRBool nsStyleBorder::IsBorderImageLoaded() const
|
||||||
PRUint32 status;
|
PRUint32 status;
|
||||||
return mBorderImage &&
|
return mBorderImage &&
|
||||||
NS_SUCCEEDED(mBorderImage->GetImageStatus(&status)) &&
|
NS_SUCCEEDED(mBorderImage->GetImageStatus(&status)) &&
|
||||||
(status & imgIRequest::STATUS_FRAME_COMPLETE);
|
(status & imgIRequest::STATUS_LOAD_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !defined(nsStyleStructInlines_h_) */
|
#endif /* !defined(nsStyleStructInlines_h_) */
|
||||||
|
|
|
@ -237,9 +237,15 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
|
||||||
currentRequest->GetImage(getter_AddRefs(mImageContainer));
|
currentRequest->GetImage(getter_AddRefs(mImageContainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXXbholley - I don't think huge images in SVGs are common enough to
|
||||||
|
// warrant worrying about the responsiveness impact of doing synchronous
|
||||||
|
// decodes. The extra code complexity of determinining when we want to
|
||||||
|
// force sync probably just isn't worth it, so always pass FLAG_SYNC_DECODE
|
||||||
nsRefPtr<gfxASurface> currentFrame;
|
nsRefPtr<gfxASurface> currentFrame;
|
||||||
if (mImageContainer)
|
if (mImageContainer)
|
||||||
mImageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
|
mImageContainer->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(currentFrame));
|
||||||
|
|
||||||
// We need to wrap the surface in a pattern to have somewhere to set the
|
// We need to wrap the surface in a pattern to have somewhere to set the
|
||||||
// graphics filter.
|
// graphics filter.
|
||||||
|
|
|
@ -333,7 +333,10 @@ void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
|
||||||
nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
|
nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
|
||||||
{
|
{
|
||||||
static_cast<nsImageBoxFrame*>(mFrame)->
|
static_cast<nsImageBoxFrame*>(mFrame)->
|
||||||
PaintImage(*aCtx, aDirtyRect, aBuilder->ToReferenceFrame(mFrame));
|
PaintImage(*aCtx, aDirtyRect, aBuilder->ToReferenceFrame(mFrame),
|
||||||
|
aBuilder->ShouldSyncDecodeImages()
|
||||||
|
? (PRUint32) imgIContainer::FLAG_SYNC_DECODE
|
||||||
|
: (PRUint32) imgIContainer::FLAG_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -359,7 +362,8 @@ nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||||
|
|
||||||
void
|
void
|
||||||
nsImageBoxFrame::PaintImage(nsIRenderingContext& aRenderingContext,
|
nsImageBoxFrame::PaintImage(nsIRenderingContext& aRenderingContext,
|
||||||
const nsRect& aDirtyRect, nsPoint aPt)
|
const nsRect& aDirtyRect, nsPoint aPt,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
nsRect rect;
|
nsRect rect;
|
||||||
GetClientRect(rect);
|
GetClientRect(rect);
|
||||||
|
@ -381,7 +385,7 @@ nsImageBoxFrame::PaintImage(nsIRenderingContext& aRenderingContext,
|
||||||
PRBool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
|
PRBool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
|
||||||
nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
|
nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
||||||
rect, dirty, hasSubRect ? &mSubRect : nsnull);
|
rect, dirty, aFlags, hasSubRect ? &mSubRect : nsnull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ public:
|
||||||
|
|
||||||
void PaintImage(nsIRenderingContext& aRenderingContext,
|
void PaintImage(nsIRenderingContext& aRenderingContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsPoint aPt);
|
nsPoint aPt, PRUint32 aFlags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
|
nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
|
||||||
|
|
|
@ -3399,7 +3399,7 @@ nsTreeBodyFrame::PaintTwisty(PRInt32 aRowIndex,
|
||||||
|
|
||||||
// Paint the image.
|
// Paint the image.
|
||||||
nsLayoutUtils::DrawSingleUnscaledImage(&aRenderingContext, image,
|
nsLayoutUtils::DrawSingleUnscaledImage(&aRenderingContext, image,
|
||||||
pt, aDirtyRect, &imageSize);
|
pt, aDirtyRect, imgIContainer::FLAG_NONE, &imageSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3530,7 +3530,8 @@ nsTreeBodyFrame::PaintImage(PRInt32 aRowIndex,
|
||||||
|
|
||||||
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
||||||
wholeImageDest, destRect, destRect.TopLeft(), aDirtyRect);
|
wholeImageDest, destRect, destRect.TopLeft(), aDirtyRect,
|
||||||
|
imgIContainer::FLAG_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the aRemainingWidth and aCurrX values.
|
// Update the aRemainingWidth and aCurrX values.
|
||||||
|
@ -3706,7 +3707,7 @@ nsTreeBodyFrame::PaintCheckbox(PRInt32 aRowIndex,
|
||||||
|
|
||||||
// Paint the image.
|
// Paint the image.
|
||||||
nsLayoutUtils::DrawSingleUnscaledImage(&aRenderingContext, image,
|
nsLayoutUtils::DrawSingleUnscaledImage(&aRenderingContext, image,
|
||||||
pt, aDirtyRect, &imageSize);
|
pt, aDirtyRect, imgIContainer::FLAG_NONE, &imageSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3771,7 +3772,8 @@ nsTreeBodyFrame::PaintProgressMeter(PRInt32 aRowIndex,
|
||||||
height*nsIDeviceContext::AppUnitsPerCSSPixel());
|
height*nsIDeviceContext::AppUnitsPerCSSPixel());
|
||||||
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
||||||
nsRect(meterRect.TopLeft(), size), meterRect, meterRect.TopLeft(), aDirtyRect);
|
nsRect(meterRect.TopLeft(), size), meterRect, meterRect.TopLeft(),
|
||||||
|
aDirtyRect, imgIContainer::FLAG_NONE);
|
||||||
} else {
|
} else {
|
||||||
aRenderingContext.FillRect(meterRect);
|
aRenderingContext.FillRect(meterRect);
|
||||||
}
|
}
|
||||||
|
@ -3791,7 +3793,8 @@ nsTreeBodyFrame::PaintProgressMeter(PRInt32 aRowIndex,
|
||||||
height*nsIDeviceContext::AppUnitsPerCSSPixel());
|
height*nsIDeviceContext::AppUnitsPerCSSPixel());
|
||||||
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
||||||
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
nsLayoutUtils::GetGraphicsFilterForFrame(this),
|
||||||
nsRect(meterRect.TopLeft(), size), meterRect, meterRect.TopLeft(), aDirtyRect);
|
nsRect(meterRect.TopLeft(), size), meterRect, meterRect.TopLeft(),
|
||||||
|
aDirtyRect, imgIContainer::FLAG_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,7 +190,7 @@ static const nsModuleComponentInfo components[] =
|
||||||
imgLoaderConstructor, },
|
imgLoaderConstructor, },
|
||||||
{ "image container",
|
{ "image container",
|
||||||
NS_IMGCONTAINER_CID,
|
NS_IMGCONTAINER_CID,
|
||||||
"@mozilla.org/image/container;2",
|
"@mozilla.org/image/container;3",
|
||||||
imgContainerConstructor, },
|
imgContainerConstructor, },
|
||||||
{ "image loader",
|
{ "image loader",
|
||||||
NS_IMGLOADER_CID,
|
NS_IMGLOADER_CID,
|
||||||
|
@ -211,7 +211,7 @@ static const nsModuleComponentInfo components[] =
|
||||||
// gif
|
// gif
|
||||||
{ "GIF Decoder",
|
{ "GIF Decoder",
|
||||||
NS_GIFDECODER2_CID,
|
NS_GIFDECODER2_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/gif",
|
"@mozilla.org/image/decoder;3?type=image/gif",
|
||||||
nsGIFDecoder2Constructor, },
|
nsGIFDecoder2Constructor, },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -219,15 +219,15 @@ static const nsModuleComponentInfo components[] =
|
||||||
// jpeg
|
// jpeg
|
||||||
{ "JPEG decoder",
|
{ "JPEG decoder",
|
||||||
NS_JPEGDECODER_CID,
|
NS_JPEGDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/jpeg",
|
"@mozilla.org/image/decoder;3?type=image/jpeg",
|
||||||
nsJPEGDecoderConstructor, },
|
nsJPEGDecoderConstructor, },
|
||||||
{ "JPEG decoder",
|
{ "JPEG decoder",
|
||||||
NS_JPEGDECODER_CID,
|
NS_JPEGDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/pjpeg",
|
"@mozilla.org/image/decoder;3?type=image/pjpeg",
|
||||||
nsJPEGDecoderConstructor, },
|
nsJPEGDecoderConstructor, },
|
||||||
{ "JPEG decoder",
|
{ "JPEG decoder",
|
||||||
NS_JPEGDECODER_CID,
|
NS_JPEGDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/jpg",
|
"@mozilla.org/image/decoder;3?type=image/jpg",
|
||||||
nsJPEGDecoderConstructor, },
|
nsJPEGDecoderConstructor, },
|
||||||
#endif
|
#endif
|
||||||
#ifdef IMG_BUILD_ENCODER_jpeg
|
#ifdef IMG_BUILD_ENCODER_jpeg
|
||||||
|
@ -242,19 +242,19 @@ static const nsModuleComponentInfo components[] =
|
||||||
// bmp
|
// bmp
|
||||||
{ "ICO Decoder",
|
{ "ICO Decoder",
|
||||||
NS_ICODECODER_CID,
|
NS_ICODECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/x-icon",
|
"@mozilla.org/image/decoder;3?type=image/x-icon",
|
||||||
nsICODecoderConstructor, },
|
nsICODecoderConstructor, },
|
||||||
{ "ICO Decoder",
|
{ "ICO Decoder",
|
||||||
NS_ICODECODER_CID,
|
NS_ICODECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/vnd.microsoft.icon",
|
"@mozilla.org/image/decoder;3?type=image/vnd.microsoft.icon",
|
||||||
nsICODecoderConstructor, },
|
nsICODecoderConstructor, },
|
||||||
{ "BMP Decoder",
|
{ "BMP Decoder",
|
||||||
NS_BMPDECODER_CID,
|
NS_BMPDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/bmp",
|
"@mozilla.org/image/decoder;3?type=image/bmp",
|
||||||
nsBMPDecoderConstructor, },
|
nsBMPDecoderConstructor, },
|
||||||
{ "BMP Decoder",
|
{ "BMP Decoder",
|
||||||
NS_BMPDECODER_CID,
|
NS_BMPDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/x-ms-bmp",
|
"@mozilla.org/image/decoder;3?type=image/x-ms-bmp",
|
||||||
nsBMPDecoderConstructor, },
|
nsBMPDecoderConstructor, },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -262,11 +262,11 @@ static const nsModuleComponentInfo components[] =
|
||||||
// png
|
// png
|
||||||
{ "PNG Decoder",
|
{ "PNG Decoder",
|
||||||
NS_PNGDECODER_CID,
|
NS_PNGDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/png",
|
"@mozilla.org/image/decoder;3?type=image/png",
|
||||||
nsPNGDecoderConstructor, },
|
nsPNGDecoderConstructor, },
|
||||||
{ "PNG Decoder",
|
{ "PNG Decoder",
|
||||||
NS_PNGDECODER_CID,
|
NS_PNGDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/x-png",
|
"@mozilla.org/image/decoder;3?type=image/x-png",
|
||||||
nsPNGDecoderConstructor, },
|
nsPNGDecoderConstructor, },
|
||||||
#endif
|
#endif
|
||||||
#ifdef IMG_BUILD_ENCODER_png
|
#ifdef IMG_BUILD_ENCODER_png
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Neil Rashbrook <neil@parkwaycc.co.uk>
|
* Neil Rashbrook <neil@parkwaycc.co.uk>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -50,8 +51,6 @@
|
||||||
#include "nsIInterfaceRequestor.h"
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
|
|
||||||
#include "imgILoad.h"
|
|
||||||
|
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
|
@ -73,6 +72,7 @@ nsBMPDecoder::nsBMPDecoder()
|
||||||
mState = eRLEStateInitial;
|
mState = eRLEStateInitial;
|
||||||
mStateData = 0;
|
mStateData = 0;
|
||||||
mLOH = WIN_HEADER_LENGTH;
|
mLOH = WIN_HEADER_LENGTH;
|
||||||
|
mError = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBMPDecoder::~nsBMPDecoder()
|
nsBMPDecoder::~nsBMPDecoder()
|
||||||
|
@ -82,31 +82,37 @@ nsBMPDecoder::~nsBMPDecoder()
|
||||||
free(mRow);
|
free(mRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsBMPDecoder::Init(imgILoad *aLoad)
|
NS_IMETHODIMP nsBMPDecoder::Init(imgIContainer *aImage,
|
||||||
|
imgIDecoderObserver *aObserver,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", aLoad));
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", aImage));
|
||||||
mObserver = do_QueryInterface(aLoad);
|
mImage = aImage;
|
||||||
|
mObserver = aObserver;
|
||||||
|
mFlags = aFlags;
|
||||||
|
|
||||||
nsresult rv;
|
// Fire OnStartDecode at init time to support bug 512435
|
||||||
mImage = do_CreateInstance("@mozilla.org/image/container;2", &rv);
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
|
||||||
if (NS_FAILED(rv))
|
mObserver->OnStartDecode(nsnull);
|
||||||
return rv;
|
|
||||||
|
|
||||||
return aLoad->SetImage(mImage);
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsBMPDecoder::Close()
|
NS_IMETHODIMP nsBMPDecoder::Close(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Close()\n"));
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Close()\n"));
|
||||||
|
|
||||||
|
// Send notifications if appropriate
|
||||||
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
|
||||||
|
!mError && !(aFlags & CLOSE_FLAG_DONTNOTIFY)) {
|
||||||
|
if (mObserver)
|
||||||
|
mObserver->OnStopFrame(nsnull, 0);
|
||||||
mImage->DecodingComplete();
|
mImage->DecodingComplete();
|
||||||
if (mObserver) {
|
if (mObserver) {
|
||||||
mObserver->OnStopFrame(nsnull, 0);
|
|
||||||
mObserver->OnStopContainer(nsnull, mImage);
|
mObserver->OnStopContainer(nsnull, mImage);
|
||||||
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
||||||
mObserver = nsnull;
|
|
||||||
}
|
}
|
||||||
mImage = nsnull;
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,29 +126,31 @@ NS_METHOD nsBMPDecoder::ReadSegCb(nsIInputStream* aIn, void* aClosure,
|
||||||
PRUint32 aCount, PRUint32 *aWriteCount)
|
PRUint32 aCount, PRUint32 *aWriteCount)
|
||||||
{
|
{
|
||||||
nsBMPDecoder *decoder = reinterpret_cast<nsBMPDecoder*>(aClosure);
|
nsBMPDecoder *decoder = reinterpret_cast<nsBMPDecoder*>(aClosure);
|
||||||
|
|
||||||
|
// Always read everything
|
||||||
*aWriteCount = aCount;
|
*aWriteCount = aCount;
|
||||||
|
|
||||||
nsresult rv = decoder->ProcessData(aFromRawSegment, aCount);
|
nsresult rv = decoder->ProcessData(aFromRawSegment, aCount);
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
// Necko doesn't propagate rvs. Set a flag before returning.
|
||||||
*aWriteCount = 0;
|
if (NS_FAILED(rv))
|
||||||
}
|
decoder->mError = PR_TRUE;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsBMPDecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount, PRUint32 *aRetval)
|
NS_IMETHODIMP nsBMPDecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount)
|
||||||
{
|
{
|
||||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::WriteFrom(%p, %lu, %p)\n", aInStr, aCount, aRetval));
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::WriteFrom(%p, %lu, %p)\n", aInStr, aCount));
|
||||||
|
|
||||||
nsresult rv = aInStr->ReadSegments(ReadSegCb, this, aCount, aRetval);
|
// Decode, watching for errors.
|
||||||
|
nsresult rv = NS_OK;
|
||||||
if (aCount != *aRetval) {
|
PRUint32 ignored;
|
||||||
*aRetval = aCount;
|
if (!mError)
|
||||||
|
rv = aInStr->ReadSegments(ReadSegCb, this, aCount, &ignored);
|
||||||
|
if (mError || NS_FAILED(rv)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
return NS_OK;
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
@ -202,8 +210,6 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||||
aBuffer += toCopy;
|
aBuffer += toCopy;
|
||||||
}
|
}
|
||||||
if (mPos == BFH_LENGTH) {
|
if (mPos == BFH_LENGTH) {
|
||||||
rv = mObserver->OnStartDecode(nsnull);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
ProcessFileHeader();
|
ProcessFileHeader();
|
||||||
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M')
|
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M')
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
@ -228,6 +234,30 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||||
mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32)
|
mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32)
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
|
||||||
|
// BMPs with negative width are invalid
|
||||||
|
// Reject extremely wide images to keep the math sane
|
||||||
|
const PRInt32 k64KWidth = 0x0000FFFF;
|
||||||
|
if (mBIH.width < 0 || mBIH.width > k64KWidth)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
PRUint32 real_height = (mBIH.height > 0) ? mBIH.height : -mBIH.height;
|
||||||
|
|
||||||
|
// Set the size and notify
|
||||||
|
rv = mImage->SetSize(mBIH.width, real_height);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
if (mObserver) {
|
||||||
|
rv = mObserver->OnStartContainer(nsnull, mImage);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have the size. If we're doing a header-only decode, we got what
|
||||||
|
// we came for.
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// We're doing a real decode.
|
||||||
|
mOldLine = mCurLine = real_height;
|
||||||
|
|
||||||
if (mBIH.bpp <= 8) {
|
if (mBIH.bpp <= 8) {
|
||||||
mNumColors = 1 << mBIH.bpp;
|
mNumColors = 1 << mBIH.bpp;
|
||||||
if (mBIH.colors && mBIH.colors < mNumColors)
|
if (mBIH.colors && mBIH.colors < mNumColors)
|
||||||
|
@ -247,18 +277,6 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||||
mBitFields.blue = 0x001F;
|
mBitFields.blue = 0x001F;
|
||||||
CalcBitShift();
|
CalcBitShift();
|
||||||
}
|
}
|
||||||
// BMPs with negative width are invalid
|
|
||||||
// Reject extremely wide images to keep the math sane
|
|
||||||
const PRInt32 k64KWidth = 0x0000FFFF;
|
|
||||||
if (mBIH.width < 0 || mBIH.width > k64KWidth)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
PRUint32 real_height = (mBIH.height > 0) ? mBIH.height : -mBIH.height;
|
|
||||||
rv = mImage->Init(mBIH.width, real_height, mObserver);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = mObserver->OnStartContainer(nsnull, mImage);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
mOldLine = mCurLine = real_height;
|
|
||||||
|
|
||||||
PRUint32 imageLength;
|
PRUint32 imageLength;
|
||||||
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
||||||
|
@ -291,9 +309,11 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||||
memset(mImageData, 0, imageLength);
|
memset(mImageData, 0, imageLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mObserver) {
|
||||||
mObserver->OnStartFrame(nsnull, 0);
|
mObserver->OnStartFrame(nsnull, 0);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
PRUint8 bpc; // bytes per color
|
PRUint8 bpc; // bytes per color
|
||||||
bpc = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4; // OS/2 Bitmaps have no padding byte
|
bpc = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4; // OS/2 Bitmaps have no padding byte
|
||||||
if (mColors && (mPos >= mLOH && (mPos < (mLOH + mNumColors * bpc)))) {
|
if (mColors && (mPos >= mLOH && (mPos < (mLOH + mNumColors * bpc)))) {
|
||||||
|
@ -599,6 +619,7 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||||
rv = mImage->FrameUpdated(0, r);
|
rv = mImage->FrameUpdated(0, r);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (mObserver)
|
||||||
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
||||||
mOldLine = mCurLine;
|
mOldLine = mCurLine;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -169,6 +170,7 @@ private:
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver;
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
|
PRUint32 mFlags;
|
||||||
|
|
||||||
PRUint32 mPos;
|
PRUint32 mPos;
|
||||||
|
|
||||||
|
@ -192,6 +194,7 @@ private:
|
||||||
|
|
||||||
ERLEState mState; ///< Maintains the current state of the RLE decoding
|
ERLEState mState; ///< Maintains the current state of the RLE decoding
|
||||||
PRUint32 mStateData;///< Decoding information that is needed depending on mState
|
PRUint32 mStateData;///< Decoding information that is needed depending on mState
|
||||||
|
PRBool mError; ///< Did we hit an error?
|
||||||
|
|
||||||
/** Set mBFH from the raw data in mRawBuf, converting from little-endian
|
/** Set mBFH from the raw data in mRawBuf, converting from little-endian
|
||||||
* data to native data as necessary */
|
* data to native data as necessary */
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||||
* Christian Biesinger <cbiesinger@web.de>
|
* Christian Biesinger <cbiesinger@web.de>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -48,7 +49,6 @@
|
||||||
#include "nsIComponentManager.h"
|
#include "nsIComponentManager.h"
|
||||||
#include "imgIContainerObserver.h"
|
#include "imgIContainerObserver.h"
|
||||||
|
|
||||||
#include "imgILoad.h"
|
|
||||||
#include "nsIInterfaceRequestor.h"
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
|
|
||||||
|
@ -82,45 +82,55 @@ nsICODecoder::nsICODecoder()
|
||||||
mColors = nsnull;
|
mColors = nsnull;
|
||||||
mRow = nsnull;
|
mRow = nsnull;
|
||||||
mHaveAlphaData = mDecodingAndMask = PR_FALSE;
|
mHaveAlphaData = mDecodingAndMask = PR_FALSE;
|
||||||
|
mError = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsICODecoder::~nsICODecoder()
|
nsICODecoder::~nsICODecoder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsICODecoder::Init(imgILoad *aLoad)
|
NS_IMETHODIMP nsICODecoder::Init(imgIContainer *aImage,
|
||||||
|
imgIDecoderObserver *aObserver,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
mObserver = do_QueryInterface(aLoad);
|
// Grab parameters
|
||||||
|
mImage = aImage;
|
||||||
|
mObserver = aObserver;
|
||||||
|
mFlags = aFlags;
|
||||||
|
|
||||||
mImage = do_CreateInstance("@mozilla.org/image/container;2");
|
// Fire OnStartDecode at init time to support bug 512435
|
||||||
if (!mImage)
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
mObserver->OnStartDecode(nsnull);
|
||||||
|
|
||||||
return aLoad->SetImage(mImage);
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsICODecoder::Close()
|
NS_IMETHODIMP nsICODecoder::Close(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
// Send notifications if appropriate
|
||||||
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
|
||||||
|
!mError && !(aFlags & CLOSE_FLAG_DONTNOTIFY)) {
|
||||||
// Tell the image that it's data has been updated
|
// Tell the image that it's data has been updated
|
||||||
nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
|
nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
|
||||||
nsresult rv = mImage->FrameUpdated(0, r);
|
rv = mImage->FrameUpdated(0, r);
|
||||||
|
|
||||||
mImage->DecodingComplete();
|
|
||||||
|
|
||||||
if (mObserver) {
|
if (mObserver) {
|
||||||
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
||||||
mObserver->OnStopFrame(nsnull, 0);
|
mObserver->OnStopFrame(nsnull, 0);
|
||||||
|
}
|
||||||
|
mImage->DecodingComplete();
|
||||||
|
if (mObserver) {
|
||||||
mObserver->OnStopContainer(nsnull, 0);
|
mObserver->OnStopContainer(nsnull, 0);
|
||||||
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
||||||
mObserver = nsnull;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mImage = nsnull;
|
|
||||||
|
|
||||||
mPos = 0;
|
mPos = 0;
|
||||||
|
|
||||||
delete[] mColors;
|
delete[] mColors;
|
||||||
mColors = nsnull;
|
|
||||||
|
|
||||||
mCurLine = 0;
|
mCurLine = 0;
|
||||||
mRowBytes = 0;
|
mRowBytes = 0;
|
||||||
|
@ -147,13 +157,29 @@ NS_METHOD nsICODecoder::ReadSegCb(nsIInputStream* aIn, void* aClosure,
|
||||||
const char* aFromRawSegment, PRUint32 aToOffset,
|
const char* aFromRawSegment, PRUint32 aToOffset,
|
||||||
PRUint32 aCount, PRUint32 *aWriteCount) {
|
PRUint32 aCount, PRUint32 *aWriteCount) {
|
||||||
nsICODecoder *decoder = reinterpret_cast<nsICODecoder*>(aClosure);
|
nsICODecoder *decoder = reinterpret_cast<nsICODecoder*>(aClosure);
|
||||||
|
|
||||||
|
// Always read everything
|
||||||
*aWriteCount = aCount;
|
*aWriteCount = aCount;
|
||||||
return decoder->ProcessData(aFromRawSegment, aCount);
|
|
||||||
|
// Process
|
||||||
|
nsresult rv = decoder->ProcessData(aFromRawSegment, aCount);
|
||||||
|
|
||||||
|
// rvs might not propagate correctly. Set a flag before returning.
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
decoder->mError = PR_TRUE;
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsICODecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount, PRUint32 *aRetval)
|
NS_IMETHODIMP nsICODecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount)
|
||||||
{
|
{
|
||||||
return aInStr->ReadSegments(ReadSegCb, this, aCount, aRetval);
|
// Decode, watching for errors
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
PRUint32 ignored;
|
||||||
|
if (!mError)
|
||||||
|
rv = aInStr->ReadSegments(ReadSegCb, this, aCount, &ignored);
|
||||||
|
if (mError || NS_FAILED(rv))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||||
|
@ -240,10 +266,17 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
if (mPos == mImageOffset + BITMAPINFOSIZE) {
|
if (mPos == mImageOffset + BITMAPINFOSIZE) {
|
||||||
rv = mObserver->OnStartDecode(nsnull);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
ProcessInfoHeader();
|
ProcessInfoHeader();
|
||||||
|
rv = mImage->SetSize(mDirEntry.mWidth, mDirEntry.mHeight);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
if (mObserver) {
|
||||||
|
rv = mObserver->OnStartContainer(nsnull, mImage);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
if (mBIH.bpp <= 8) {
|
if (mBIH.bpp <= 8) {
|
||||||
switch (mBIH.bpp) {
|
switch (mBIH.bpp) {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -264,9 +297,6 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = mImage->Init(mDirEntry.mWidth, mDirEntry.mHeight, mObserver);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
if (mIsCursor) {
|
if (mIsCursor) {
|
||||||
nsCOMPtr<nsIProperties> props(do_QueryInterface(mImage));
|
nsCOMPtr<nsIProperties> props(do_QueryInterface(mImage));
|
||||||
if (props) {
|
if (props) {
|
||||||
|
@ -283,9 +313,6 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = mObserver->OnStartContainer(nsnull, mImage);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
mCurLine = mDirEntry.mHeight;
|
mCurLine = mDirEntry.mHeight;
|
||||||
mRow = (PRUint8*)malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
|
mRow = (PRUint8*)malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
|
||||||
// +4 because the line is padded to a 4 bit boundary, but I don't want
|
// +4 because the line is padded to a 4 bit boundary, but I don't want
|
||||||
|
@ -299,9 +326,11 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||||
gfxASurface::ImageFormatARGB32, (PRUint8**)&mImageData, &imageLength);
|
gfxASurface::ImageFormatARGB32, (PRUint8**)&mImageData, &imageLength);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (mObserver) {
|
||||||
mObserver->OnStartFrame(nsnull, 0);
|
mObserver->OnStartFrame(nsnull, 0);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) &&
|
if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) &&
|
||||||
(mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
|
(mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -93,8 +94,9 @@ private:
|
||||||
PRUint32 CalcAlphaRowSize();
|
PRUint32 CalcAlphaRowSize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver;
|
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
PRUint32 mFlags;
|
||||||
|
|
||||||
PRUint32 mPos;
|
PRUint32 mPos;
|
||||||
PRUint16 mNumIcons;
|
PRUint16 mNumIcons;
|
||||||
|
@ -119,6 +121,7 @@ private:
|
||||||
PRPackedBool mHaveAlphaData;
|
PRPackedBool mHaveAlphaData;
|
||||||
PRPackedBool mIsCursor;
|
PRPackedBool mIsCursor;
|
||||||
PRPackedBool mDecodingAndMask;
|
PRPackedBool mDecodingAndMask;
|
||||||
|
PRPackedBool mError;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Chris Saari <saari@netscape.com>
|
* Chris Saari <saari@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -81,8 +82,6 @@ mailing address.
|
||||||
#include "nsIComponentManager.h"
|
#include "nsIComponentManager.h"
|
||||||
#include "imgIContainerObserver.h"
|
#include "imgIContainerObserver.h"
|
||||||
|
|
||||||
#include "imgILoad.h"
|
|
||||||
|
|
||||||
#include "gfxColor.h"
|
#include "gfxColor.h"
|
||||||
#include "gfxPlatform.h"
|
#include "gfxPlatform.h"
|
||||||
#include "qcms.h"
|
#include "qcms.h"
|
||||||
|
@ -122,6 +121,7 @@ nsGIFDecoder2::nsGIFDecoder2()
|
||||||
, mLastFlushedPass(0)
|
, mLastFlushedPass(0)
|
||||||
, mGIFOpen(PR_FALSE)
|
, mGIFOpen(PR_FALSE)
|
||||||
, mSawTransparency(PR_FALSE)
|
, mSawTransparency(PR_FALSE)
|
||||||
|
, mError(PR_FALSE)
|
||||||
{
|
{
|
||||||
// Clear out the structure, excluding the arrays
|
// Clear out the structure, excluding the arrays
|
||||||
memset(&mGIFStruct, 0, sizeof(mGIFStruct));
|
memset(&mGIFStruct, 0, sizeof(mGIFStruct));
|
||||||
|
@ -129,7 +129,6 @@ nsGIFDecoder2::nsGIFDecoder2()
|
||||||
|
|
||||||
nsGIFDecoder2::~nsGIFDecoder2()
|
nsGIFDecoder2::~nsGIFDecoder2()
|
||||||
{
|
{
|
||||||
Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -137,13 +136,21 @@ nsGIFDecoder2::~nsGIFDecoder2()
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
/* void init (in imgILoad aLoad); */
|
/* void init (in imgIContainer aImage,
|
||||||
NS_IMETHODIMP nsGIFDecoder2::Init(imgILoad *aLoad)
|
in imgIDecoderObserver aObsever,
|
||||||
|
in unsigned long aFlags); */
|
||||||
|
NS_IMETHODIMP nsGIFDecoder2::Init(imgIContainer *aImage,
|
||||||
|
imgIDecoderObserver *aObserver,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
mObserver = do_QueryInterface(aLoad);
|
// Store parameters
|
||||||
|
mImageContainer = aImage;
|
||||||
|
mObserver = aObserver;
|
||||||
|
mFlags = aFlags;
|
||||||
|
|
||||||
mImageContainer = do_CreateInstance("@mozilla.org/image/container;2");
|
// Fire OnStartDecode at init time to support bug 512435
|
||||||
aLoad->SetImage(mImageContainer);
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
|
||||||
|
mObserver->OnStartDecode(nsnull);
|
||||||
|
|
||||||
// Start with the version (GIF89a|GIF87a)
|
// Start with the version (GIF89a|GIF87a)
|
||||||
mGIFStruct.state = gif_type;
|
mGIFStruct.state = gif_type;
|
||||||
|
@ -159,14 +166,20 @@ NS_IMETHODIMP nsGIFDecoder2::Init(imgILoad *aLoad)
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
/* void close (); */
|
/* void close (); */
|
||||||
NS_IMETHODIMP nsGIFDecoder2::Close()
|
NS_IMETHODIMP nsGIFDecoder2::Close(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
|
// Send notifications if appropriate
|
||||||
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
|
||||||
|
!mError && !(aFlags & CLOSE_FLAG_DONTNOTIFY)) {
|
||||||
if (mCurrentFrame == mGIFStruct.images_decoded)
|
if (mCurrentFrame == mGIFStruct.images_decoded)
|
||||||
EndImageFrame();
|
EndImageFrame();
|
||||||
EndGIF();
|
EndGIF(/* aSuccess = */ PR_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
PR_FREEIF(mGIFStruct.local_colormap);
|
PR_FREEIF(mGIFStruct.local_colormap);
|
||||||
|
|
||||||
|
mImageContainer = nsnull;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +192,7 @@ NS_IMETHODIMP nsGIFDecoder2::Flush()
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
/* static callback from nsIInputStream::ReadSegments */
|
/* static callback from nsIInputStream::ReadSegments */
|
||||||
static NS_METHOD ReadDataOut(nsIInputStream* in,
|
NS_METHOD nsGIFDecoder2::ReadDataOut(nsIInputStream* in,
|
||||||
void* closure,
|
void* closure,
|
||||||
const char* fromRawSegment,
|
const char* fromRawSegment,
|
||||||
PRUint32 toOffset,
|
PRUint32 toOffset,
|
||||||
|
@ -187,12 +200,36 @@ static NS_METHOD ReadDataOut(nsIInputStream* in,
|
||||||
PRUint32 *writeCount)
|
PRUint32 *writeCount)
|
||||||
{
|
{
|
||||||
nsGIFDecoder2 *decoder = static_cast<nsGIFDecoder2*>(closure);
|
nsGIFDecoder2 *decoder = static_cast<nsGIFDecoder2*>(closure);
|
||||||
nsresult rv = decoder->ProcessData((unsigned char*)fromRawSegment, count, writeCount);
|
|
||||||
|
// Always read everything
|
||||||
|
*writeCount = count;
|
||||||
|
|
||||||
|
// Process
|
||||||
|
nsresult rv = decoder->ProcessData((unsigned char*)fromRawSegment, count);
|
||||||
|
|
||||||
|
// We do some fine-grained error control here. If we have at least one frame
|
||||||
|
// of an animated gif, we still want to display it (mostly for legacy reasons).
|
||||||
|
// libpr0n code is strict, so we have to lie and tell it we were successful. So
|
||||||
|
// if we have something to salvage, we send off final decode notifications, and
|
||||||
|
// pretend that we're decoded. Otherwise, we set mError.
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
*writeCount = 0;
|
|
||||||
return rv;
|
// Determine if we want to salvage the situation
|
||||||
|
PRUint32 numFrames = 0;
|
||||||
|
if (decoder->mImageContainer)
|
||||||
|
decoder->mImageContainer->GetNumFrames(&numFrames);
|
||||||
|
|
||||||
|
// If we're salvaging, send off notifications
|
||||||
|
if (numFrames > 1) { // XXXbholley - this is from the old code, but why not > 0?
|
||||||
|
decoder->EndGIF(/* aSuccess = */ PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, set mError
|
||||||
|
else
|
||||||
|
decoder->mError = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Necko is dubious with callbacks, so we don't use rvs to propagate errors.
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,43 +281,36 @@ nsGIFDecoder2::FlushImageData()
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
nsresult nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count, PRUint32 *_retval)
|
nsresult nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count)
|
||||||
{
|
{
|
||||||
// Push the data to the GIF decoder
|
// Push the data to the GIF decoder
|
||||||
|
|
||||||
nsresult rv = GifWrite(data, count);
|
nsresult rv = GifWrite(data, count);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Flushing is only needed for first frame
|
// Flushing is only needed for first frame
|
||||||
if (!mGIFStruct.images_decoded) {
|
if (!mGIFStruct.images_decoded) {
|
||||||
rv = FlushImageData();
|
rv = FlushImageData();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
mLastFlushedRow = mCurrentRow;
|
mLastFlushedRow = mCurrentRow;
|
||||||
mLastFlushedPass = mCurrentPass;
|
mLastFlushedPass = mCurrentPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
*_retval = count;
|
return NS_OK;
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
|
/* void writeFrom (in nsIInputStream inStr, in unsigned long count); */
|
||||||
NS_IMETHODIMP nsGIFDecoder2::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
|
NS_IMETHODIMP nsGIFDecoder2::WriteFrom(nsIInputStream *inStr, PRUint32 count)
|
||||||
{
|
{
|
||||||
nsresult rv = inStr->ReadSegments(ReadDataOut, this, count, _retval);
|
// Decode, watching for errors
|
||||||
|
nsresult rv = NS_OK;
|
||||||
/* necko doesn't propagate the errors from ReadDataOut - take matters
|
PRUint32 ignored;
|
||||||
into our own hands. if we have at least one frame of an animated
|
if (!mError)
|
||||||
gif, then return success so we keep displaying as much as possible. */
|
rv = inStr->ReadSegments(nsGIFDecoder2::ReadDataOut, this,
|
||||||
if (mGIFStruct.state == gif_error || mGIFStruct.state == gif_oom) {
|
count, &ignored);
|
||||||
PRUint32 numFrames = 0;
|
if (mError || NS_FAILED(rv))
|
||||||
if (mImageContainer)
|
return NS_ERROR_FAILURE;
|
||||||
mImageContainer->GetNumFrames(&numFrames);
|
return NS_OK;
|
||||||
if (numFrames <= 1)
|
|
||||||
rv = NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,30 +324,33 @@ void nsGIFDecoder2::BeginGIF()
|
||||||
if (mGIFOpen)
|
if (mGIFOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mObserver)
|
mGIFOpen = PR_TRUE;
|
||||||
mObserver->OnStartDecode(nsnull);
|
|
||||||
|
|
||||||
mImageContainer->Init(mGIFStruct.screen_width, mGIFStruct.screen_height, mObserver);
|
|
||||||
|
|
||||||
|
mImageContainer->SetSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
|
||||||
if (mObserver)
|
if (mObserver)
|
||||||
mObserver->OnStartContainer(nsnull, mImageContainer);
|
mObserver->OnStartContainer(nsnull, mImageContainer);
|
||||||
|
|
||||||
mGIFOpen = PR_TRUE;
|
// If we're doing a header-only decode, we have what we came for
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void nsGIFDecoder2::EndGIF()
|
void nsGIFDecoder2::EndGIF(PRBool aSuccess)
|
||||||
{
|
{
|
||||||
if (!mGIFOpen)
|
if (!mGIFOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (aSuccess)
|
||||||
|
mImageContainer->DecodingComplete();
|
||||||
|
|
||||||
if (mObserver) {
|
if (mObserver) {
|
||||||
mObserver->OnStopContainer(nsnull, mImageContainer);
|
mObserver->OnStopContainer(nsnull, mImageContainer);
|
||||||
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
|
||||||
|
nsnull);
|
||||||
}
|
}
|
||||||
|
|
||||||
mImageContainer->SetLoopCount(mGIFStruct.loop_count);
|
mImageContainer->SetLoopCount(mGIFStruct.loop_count);
|
||||||
mImageContainer->DecodingComplete();
|
|
||||||
|
|
||||||
mGIFOpen = PR_FALSE;
|
mGIFOpen = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -335,7 +368,10 @@ nsresult nsGIFDecoder2::BeginImageFrame(gfx_depth aDepth)
|
||||||
PRUint32 imgCurFrame;
|
PRUint32 imgCurFrame;
|
||||||
mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
|
mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
|
||||||
nsIntRect r(0, 0, imgWidth, mGIFStruct.y_offset);
|
nsIntRect r(0, 0, imgWidth, mGIFStruct.y_offset);
|
||||||
mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
|
if (mObserver)
|
||||||
|
mObserver->OnDataAvailable(nsnull,
|
||||||
|
imgCurFrame == PRUint32(mGIFStruct.images_decoded),
|
||||||
|
&r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +430,10 @@ void nsGIFDecoder2::EndImageFrame()
|
||||||
nsIntRect r(0, realFrameHeight,
|
nsIntRect r(0, realFrameHeight,
|
||||||
mGIFStruct.screen_width,
|
mGIFStruct.screen_width,
|
||||||
mGIFStruct.screen_height - realFrameHeight);
|
mGIFStruct.screen_height - realFrameHeight);
|
||||||
mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
|
if (mObserver)
|
||||||
|
mObserver->OnDataAvailable(nsnull,
|
||||||
|
imgCurFrame == PRUint32(mGIFStruct.images_decoded),
|
||||||
|
&r);
|
||||||
}
|
}
|
||||||
// This transparency check is only valid for first frame
|
// This transparency check is only valid for first frame
|
||||||
if (mGIFStruct.is_transparent && !mSawTransparency) {
|
if (mGIFStruct.is_transparent && !mSawTransparency) {
|
||||||
|
@ -1051,6 +1090,10 @@ nsresult nsGIFDecoder2::GifWrite(const PRUint8 *buf, PRUint32 len)
|
||||||
}
|
}
|
||||||
// Create the image container with the right size.
|
// Create the image container with the right size.
|
||||||
BeginGIF();
|
BeginGIF();
|
||||||
|
|
||||||
|
// If we were doing header-only, we're done
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Work around more broken GIF files that have zero image
|
/* Work around more broken GIF files that have zero image
|
||||||
|
@ -1182,12 +1225,12 @@ nsresult nsGIFDecoder2::GifWrite(const PRUint8 *buf, PRUint32 len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_done:
|
case gif_done:
|
||||||
EndGIF();
|
EndGIF(/* aSuccess = */ PR_TRUE);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case gif_error:
|
case gif_error:
|
||||||
EndGIF();
|
EndGIF(/* aSuccess = */ PR_FALSE);
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1203,7 +1246,7 @@ nsresult nsGIFDecoder2::GifWrite(const PRUint8 *buf, PRUint32 len)
|
||||||
|
|
||||||
// if an error state is set but no data remains, code flow reaches here
|
// if an error state is set but no data remains, code flow reaches here
|
||||||
if (mGIFStruct.state == gif_error) {
|
if (mGIFStruct.state == gif_error) {
|
||||||
EndGIF();
|
EndGIF(/* aSuccess = */ PR_FALSE);
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Chris Saari <saari@netscape.com>
|
* Chris Saari <saari@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -67,14 +68,20 @@ public:
|
||||||
nsGIFDecoder2();
|
nsGIFDecoder2();
|
||||||
~nsGIFDecoder2();
|
~nsGIFDecoder2();
|
||||||
|
|
||||||
nsresult ProcessData(unsigned char *data, PRUint32 count, PRUint32 *_retval);
|
nsresult ProcessData(unsigned char *data, PRUint32 count);
|
||||||
|
static NS_METHOD ReadDataOut(nsIInputStream* in,
|
||||||
|
void* closure,
|
||||||
|
const char* fromRawSegment,
|
||||||
|
PRUint32 toOffset,
|
||||||
|
PRUint32 count,
|
||||||
|
PRUint32 *writeCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* These functions will be called when the decoder has a decoded row,
|
/* These functions will be called when the decoder has a decoded row,
|
||||||
* frame size information, etc. */
|
* frame size information, etc. */
|
||||||
|
|
||||||
void BeginGIF();
|
void BeginGIF();
|
||||||
void EndGIF();
|
void EndGIF(PRBool aSuccess);
|
||||||
nsresult BeginImageFrame(gfx_depth aDepth);
|
nsresult BeginImageFrame(gfx_depth aDepth);
|
||||||
void EndImageFrame();
|
void EndImageFrame();
|
||||||
nsresult FlushImageData();
|
nsresult FlushImageData();
|
||||||
|
@ -87,7 +94,8 @@ private:
|
||||||
inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
|
inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
|
||||||
|
|
||||||
nsCOMPtr<imgIContainer> mImageContainer;
|
nsCOMPtr<imgIContainer> mImageContainer;
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
PRUint32 mFlags;
|
||||||
PRInt32 mCurrentRow;
|
PRInt32 mCurrentRow;
|
||||||
PRInt32 mLastFlushedRow;
|
PRInt32 mLastFlushedRow;
|
||||||
|
|
||||||
|
@ -105,6 +113,7 @@ private:
|
||||||
PRUint8 mColorMask; // Apply this to the pixel to keep within colormap
|
PRUint8 mColorMask; // Apply this to the pixel to keep within colormap
|
||||||
PRPackedBool mGIFOpen;
|
PRPackedBool mGIFOpen;
|
||||||
PRPackedBool mSawTransparency;
|
PRPackedBool mSawTransparency;
|
||||||
|
PRPackedBool mError;
|
||||||
|
|
||||||
gif_struct mGIFStruct;
|
gif_struct mGIFStruct;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Scott MacGregor <mscott@netscape.com>
|
* Scott MacGregor <mscott@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -41,13 +42,13 @@
|
||||||
#include "nsIInputStream.h"
|
#include "nsIInputStream.h"
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "imgIContainerObserver.h"
|
#include "imgIContainerObserver.h"
|
||||||
#include "imgILoad.h"
|
|
||||||
#include "nspr.h"
|
#include "nspr.h"
|
||||||
#include "nsIComponentManager.h"
|
#include "nsIComponentManager.h"
|
||||||
#include "nsRect.h"
|
#include "nsRect.h"
|
||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
|
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
|
#include "ImageErrors.h"
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ADDREF(nsIconDecoder)
|
NS_IMPL_THREADSAFE_ADDREF(nsIconDecoder)
|
||||||
NS_IMPL_THREADSAFE_RELEASE(nsIconDecoder)
|
NS_IMPL_THREADSAFE_RELEASE(nsIconDecoder)
|
||||||
|
@ -56,8 +57,20 @@ NS_INTERFACE_MAP_BEGIN(nsIconDecoder)
|
||||||
NS_INTERFACE_MAP_ENTRY(imgIDecoder)
|
NS_INTERFACE_MAP_ENTRY(imgIDecoder)
|
||||||
NS_INTERFACE_MAP_END_THREADSAFE
|
NS_INTERFACE_MAP_END_THREADSAFE
|
||||||
|
|
||||||
nsIconDecoder::nsIconDecoder()
|
|
||||||
|
nsIconDecoder::nsIconDecoder() :
|
||||||
|
mImage(nsnull),
|
||||||
|
mObserver(nsnull),
|
||||||
|
mFlags(imgIDecoder::DECODER_FLAG_NONE),
|
||||||
|
mWidth(-1),
|
||||||
|
mHeight(-1),
|
||||||
|
mPixBytesRead(0),
|
||||||
|
mPixBytesTotal(0),
|
||||||
|
mImageData(nsnull),
|
||||||
|
mState(iconStateStart),
|
||||||
|
mNotifiedDone(PR_FALSE)
|
||||||
{
|
{
|
||||||
|
// Nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIconDecoder::~nsIconDecoder()
|
nsIconDecoder::~nsIconDecoder()
|
||||||
|
@ -66,29 +79,33 @@ nsIconDecoder::~nsIconDecoder()
|
||||||
|
|
||||||
/** imgIDecoder methods **/
|
/** imgIDecoder methods **/
|
||||||
|
|
||||||
NS_IMETHODIMP nsIconDecoder::Init(imgILoad *aLoad)
|
NS_IMETHODIMP nsIconDecoder::Init(imgIContainer *aImage,
|
||||||
|
imgIDecoderObserver *aObserver,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
mObserver = do_QueryInterface(aLoad); // we're holding 2 strong refs to the request.
|
|
||||||
|
|
||||||
mImage = do_CreateInstance("@mozilla.org/image/container;2");
|
// Grab parameters
|
||||||
if (!mImage) return NS_ERROR_OUT_OF_MEMORY;
|
mImage = aImage;
|
||||||
|
mObserver = aObserver;
|
||||||
|
mFlags = aFlags;
|
||||||
|
|
||||||
aLoad->SetImage(mImage);
|
// Fire OnStartDecode at init time to support bug 512435
|
||||||
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
|
||||||
|
mObserver->OnStartDecode(nsnull);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsIconDecoder::Close()
|
NS_IMETHODIMP nsIconDecoder::Close(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
mImage->DecodingComplete();
|
// If we haven't notified of completion yet for a full/success decode, we
|
||||||
|
// didn't finish. Notify in error mode
|
||||||
if (mObserver)
|
if (!(aFlags & CLOSE_FLAG_DONTNOTIFY) &&
|
||||||
{
|
!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
|
||||||
mObserver->OnStopFrame(nsnull, 0);
|
!mNotifiedDone)
|
||||||
mObserver->OnStopContainer(nsnull, mImage);
|
NotifyDone(/* aSuccess = */ PR_FALSE);
|
||||||
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mImage = nsnull;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,51 +114,155 @@ NS_IMETHODIMP nsIconDecoder::Flush()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsIconDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
|
static nsresult
|
||||||
|
WriteIconData(nsIInputStream *aInStream, void *aClosure, const char *aFromSegment,
|
||||||
|
PRUint32 aToOffset, PRUint32 aCount, PRUint32 *aWriteCount)
|
||||||
{
|
{
|
||||||
// read the header from the input stram...
|
nsresult rv;
|
||||||
PRUint32 readLen;
|
|
||||||
PRUint8 header[2];
|
|
||||||
nsresult rv = inStr->Read((char*)header, 2, &readLen);
|
|
||||||
NS_ENSURE_TRUE(readLen == 2, NS_ERROR_UNEXPECTED); // w, h
|
|
||||||
count -= 2;
|
|
||||||
|
|
||||||
PRInt32 w = header[0];
|
// We always read everything
|
||||||
PRInt32 h = header[1];
|
*aWriteCount = aCount;
|
||||||
NS_ENSURE_TRUE(w > 0 && h > 0, NS_ERROR_UNEXPECTED);
|
|
||||||
|
|
||||||
if (mObserver)
|
// We put this here to avoid errors about crossing initialization with case
|
||||||
mObserver->OnStartDecode(nsnull);
|
// jumps on linux.
|
||||||
mImage->Init(w, h, mObserver);
|
PRUint32 bytesToRead = 0;
|
||||||
if (mObserver)
|
|
||||||
mObserver->OnStartContainer(nsnull, mImage);
|
|
||||||
|
|
||||||
PRUint32 imageLen;
|
// Grab the parameters
|
||||||
PRUint8 *imageData;
|
nsIconDecoder *decoder = static_cast<nsIconDecoder*>(aClosure);
|
||||||
|
|
||||||
rv = mImage->AppendFrame(0, 0, w, h, gfxASurface::ImageFormatARGB32, &imageData, &imageLen);
|
// Performance isn't critical here, so our update rectangle is
|
||||||
if (NS_FAILED(rv))
|
// always the full icon
|
||||||
|
nsIntRect r(0, 0, decoder->mWidth, decoder->mHeight);
|
||||||
|
|
||||||
|
// Loop until the input data is gone
|
||||||
|
while (aCount > 0) {
|
||||||
|
switch (decoder->mState) {
|
||||||
|
case iconStateStart:
|
||||||
|
|
||||||
|
// Grab the width
|
||||||
|
decoder->mWidth = (PRUint8)*aFromSegment;
|
||||||
|
|
||||||
|
// Book Keeping
|
||||||
|
aFromSegment++;
|
||||||
|
aCount--;
|
||||||
|
decoder->mState = iconStateHaveHeight;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case iconStateHaveHeight:
|
||||||
|
|
||||||
|
// Grab the Height
|
||||||
|
decoder->mHeight = (PRUint8)*aFromSegment;
|
||||||
|
|
||||||
|
// Set up the container and signal
|
||||||
|
decoder->mImage->SetSize(decoder->mWidth,
|
||||||
|
decoder->mHeight);
|
||||||
|
if (decoder->mObserver)
|
||||||
|
decoder->mObserver->OnStartContainer(nsnull, decoder->mImage);
|
||||||
|
|
||||||
|
// If We're doing a header-only decode, we're done
|
||||||
|
if (decoder->mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) {
|
||||||
|
decoder->mState = iconStateFinished;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the frame and signal
|
||||||
|
rv = decoder->mImage->AppendFrame(0, 0,
|
||||||
|
decoder->mWidth,
|
||||||
|
decoder->mHeight,
|
||||||
|
gfxASurface::ImageFormatARGB32,
|
||||||
|
&decoder->mImageData,
|
||||||
|
&decoder->mPixBytesTotal);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
decoder->mState = iconStateError;
|
||||||
return rv;
|
return rv;
|
||||||
|
}
|
||||||
|
if (decoder->mObserver)
|
||||||
|
decoder->mObserver->OnStartFrame(nsnull, 0);
|
||||||
|
|
||||||
if (mObserver)
|
// Book Keeping
|
||||||
mObserver->OnStartFrame(nsnull, 0);
|
aFromSegment++;
|
||||||
|
aCount--;
|
||||||
|
decoder->mState = iconStateReadPixels;
|
||||||
|
break;
|
||||||
|
|
||||||
// Ensure that there enough in the inputStream
|
case iconStateReadPixels:
|
||||||
NS_ENSURE_TRUE(count >= imageLen, NS_ERROR_UNEXPECTED);
|
|
||||||
|
|
||||||
// Read the image data direct into the frame data
|
// How many bytes are we reading?
|
||||||
rv = inStr->Read((char*)imageData, imageLen, &readLen);
|
bytesToRead = PR_MAX(aCount,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
decoder->mPixBytesTotal - decoder->mPixBytesRead);
|
||||||
NS_ENSURE_TRUE(readLen == imageLen, NS_ERROR_UNEXPECTED);
|
|
||||||
|
|
||||||
// Notify the image...
|
// Copy the bytes
|
||||||
nsIntRect r(0, 0, w, h);
|
memcpy(decoder->mImageData + decoder->mPixBytesRead,
|
||||||
rv = mImage->FrameUpdated(0, r);
|
aFromSegment, bytesToRead);
|
||||||
if (NS_FAILED(rv))
|
|
||||||
|
// Notify
|
||||||
|
rv = decoder->mImage->FrameUpdated(0, r);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
decoder->mState = iconStateError;
|
||||||
return rv;
|
return rv;
|
||||||
|
}
|
||||||
|
if (decoder->mObserver)
|
||||||
|
decoder->mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
||||||
|
|
||||||
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
// Book Keeping
|
||||||
|
aFromSegment += bytesToRead;
|
||||||
|
aCount -= bytesToRead;
|
||||||
|
decoder->mPixBytesRead += bytesToRead;
|
||||||
|
|
||||||
|
// If we've got all the pixel bytes, we're finished
|
||||||
|
if (decoder->mPixBytesRead == decoder->mPixBytesTotal) {
|
||||||
|
decoder->NotifyDone(/* aSuccess = */ PR_TRUE);
|
||||||
|
decoder->mState = iconStateFinished;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case iconStateFinished:
|
||||||
|
|
||||||
|
// Consume all excess data silently
|
||||||
|
aCount = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case iconStateError:
|
||||||
|
return NS_IMAGELIB_ERROR_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsIconDecoder::NotifyDone(PRBool aSuccess)
|
||||||
|
{
|
||||||
|
// We should only call this once
|
||||||
|
NS_ABORT_IF_FALSE(!mNotifiedDone, "Calling NotifyDone twice");
|
||||||
|
|
||||||
|
// Notify
|
||||||
|
if (mObserver)
|
||||||
|
mObserver->OnStopFrame(nsnull, 0);
|
||||||
|
if (aSuccess)
|
||||||
|
mImage->DecodingComplete();
|
||||||
|
if (mObserver) {
|
||||||
|
mObserver->OnStopContainer(nsnull, mImage);
|
||||||
|
mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
|
||||||
|
nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flag that we've notified
|
||||||
|
mNotifiedDone = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsIconDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count)
|
||||||
|
{
|
||||||
|
// Decode, watching for errors.
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
PRUint32 ignored;
|
||||||
|
if (mState != iconStateError)
|
||||||
|
rv = inStr->ReadSegments(WriteIconData, this, count, &ignored);
|
||||||
|
if ((mState == iconStateError) || NS_FAILED(rv))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Scott MacGregor <mscott@netscape.com>
|
* Scott MacGregor <mscott@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -84,9 +85,27 @@ public:
|
||||||
nsIconDecoder();
|
nsIconDecoder();
|
||||||
virtual ~nsIconDecoder();
|
virtual ~nsIconDecoder();
|
||||||
|
|
||||||
private:
|
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
PRUint32 mFlags;
|
||||||
|
PRUint8 mWidth;
|
||||||
|
PRUint8 mHeight;
|
||||||
|
PRUint32 mPixBytesRead;
|
||||||
|
PRUint32 mPixBytesTotal;
|
||||||
|
PRUint8* mImageData;
|
||||||
|
PRUint32 mState;
|
||||||
|
|
||||||
|
PRBool mNotifiedDone;
|
||||||
|
void NotifyDone(PRBool aSuccess);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
iconStateStart = 0,
|
||||||
|
iconStateHaveHeight = 1,
|
||||||
|
iconStateReadPixels = 2,
|
||||||
|
iconStateFinished = 3,
|
||||||
|
iconStateError = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // nsIconDecoder_h__
|
#endif // nsIconDecoder_h__
|
||||||
|
|
|
@ -97,7 +97,7 @@ static const nsModuleComponentInfo components[] =
|
||||||
#ifdef USE_ICON_DECODER
|
#ifdef USE_ICON_DECODER
|
||||||
{ "icon decoder",
|
{ "icon decoder",
|
||||||
NS_ICONDECODER_CID,
|
NS_ICONDECODER_CID,
|
||||||
"@mozilla.org/image/decoder;2?type=image/icon",
|
"@mozilla.org/image/decoder;3?type=image/icon",
|
||||||
nsIconDecoderConstructor,
|
nsIconDecoderConstructor,
|
||||||
IconDecoderRegisterProc,
|
IconDecoderRegisterProc,
|
||||||
IconDecoderUnregisterProc, },
|
IconDecoderUnregisterProc, },
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <stuart@mozilla.com>
|
* Stuart Parmenter <stuart@mozilla.com>
|
||||||
* Federico Mena-Quintero <federico@novell.com>
|
* Federico Mena-Quintero <federico@novell.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -99,7 +100,8 @@ nsJPEGDecoder::nsJPEGDecoder()
|
||||||
{
|
{
|
||||||
mState = JPEG_HEADER;
|
mState = JPEG_HEADER;
|
||||||
mReading = PR_TRUE;
|
mReading = PR_TRUE;
|
||||||
mError = NS_OK;
|
mNotifiedDone = PR_FALSE;
|
||||||
|
mError = PR_FALSE;
|
||||||
mImageData = nsnull;
|
mImageData = nsnull;
|
||||||
|
|
||||||
mBytesToSkip = 0;
|
mBytesToSkip = 0;
|
||||||
|
@ -137,11 +139,22 @@ nsJPEGDecoder::~nsJPEGDecoder()
|
||||||
|
|
||||||
/** imgIDecoder methods **/
|
/** imgIDecoder methods **/
|
||||||
|
|
||||||
/* void init (in imgILoad aLoad); */
|
/* void init (in imgIContainer aImage,
|
||||||
NS_IMETHODIMP nsJPEGDecoder::Init(imgILoad *aLoad)
|
in imgIDecoderObserver aObserver,
|
||||||
|
in unsigned long aFlags); */
|
||||||
|
NS_IMETHODIMP nsJPEGDecoder::Init(imgIContainer *aImage,
|
||||||
|
imgIDecoderObserver *aObserver,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
mImageLoad = aLoad;
|
|
||||||
mObserver = do_QueryInterface(aLoad);
|
/* Grab the parameters. */
|
||||||
|
mImage = aImage;
|
||||||
|
mObserver = aObserver;
|
||||||
|
mFlags = aFlags;
|
||||||
|
|
||||||
|
/* Fire OnStartDecode at init time to support bug 512435 */
|
||||||
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
|
||||||
|
mObserver->OnStartDecode(nsnull);
|
||||||
|
|
||||||
/* We set up the normal JPEG error routines, then override error_exit. */
|
/* We set up the normal JPEG error routines, then override error_exit. */
|
||||||
mInfo.err = jpeg_std_error(&mErr.pub);
|
mInfo.err = jpeg_std_error(&mErr.pub);
|
||||||
|
@ -173,40 +186,12 @@ NS_IMETHODIMP nsJPEGDecoder::Init(imgILoad *aLoad)
|
||||||
for (PRUint32 m = 0; m < 16; m++)
|
for (PRUint32 m = 0; m < 16; m++)
|
||||||
jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
|
jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check if the request already has an image container.
|
|
||||||
* this is the case when multipart/x-mixed-replace is being downloaded
|
|
||||||
* if we already have one and it has the same width and height, reuse it.
|
|
||||||
* This is also the case when an existing container is reloading itself from
|
|
||||||
* us.
|
|
||||||
*
|
|
||||||
* If we have a mismatch in width/height for the container later on we will
|
|
||||||
* generate an error.
|
|
||||||
*/
|
|
||||||
mImageLoad->GetImage(getter_AddRefs(mImage));
|
|
||||||
|
|
||||||
if (!mImage) {
|
|
||||||
mImage = do_CreateInstance("@mozilla.org/image/container;2");
|
|
||||||
if (!mImage)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
mImageLoad->SetImage(mImage);
|
|
||||||
nsresult result = mImage->SetDiscardable("image/jpeg");
|
|
||||||
if (NS_FAILED(result)) {
|
|
||||||
mState = JPEG_ERROR;
|
|
||||||
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
(" (could not set image container to discardable)"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* void close (); */
|
/* void close (); */
|
||||||
NS_IMETHODIMP nsJPEGDecoder::Close()
|
NS_IMETHODIMP nsJPEGDecoder::Close(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
|
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
|
||||||
("[this=%p] nsJPEGDecoder::Close\n", this));
|
("[this=%p] nsJPEGDecoder::Close\n", this));
|
||||||
|
@ -216,12 +201,19 @@ NS_IMETHODIMP nsJPEGDecoder::Close()
|
||||||
|
|
||||||
jpeg_destroy_decompress(&mInfo);
|
jpeg_destroy_decompress(&mInfo);
|
||||||
|
|
||||||
if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) {
|
/* If we already know we're in an error state, don't
|
||||||
NS_WARNING("Never finished decoding the JPEG.");
|
bother flagging another one here. */
|
||||||
/* Tell imgLoader that image decoding has failed */
|
if (mError)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_OK;
|
||||||
}
|
|
||||||
|
|
||||||
|
/* If we're doing a full decode and haven't notified of completion yet,
|
||||||
|
* we must not have got everything we wanted. Send error notifications. */
|
||||||
|
if (!(aFlags & CLOSE_FLAG_DONTNOTIFY) &&
|
||||||
|
!(mFlags && imgIDecoder::DECODER_FLAG_HEADERONLY) &&
|
||||||
|
!mNotifiedDone)
|
||||||
|
NotifyDone(/* aSuccess = */ PR_FALSE);
|
||||||
|
|
||||||
|
/* Otherwise, no problems. */
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,9 +222,8 @@ NS_IMETHODIMP nsJPEGDecoder::Flush()
|
||||||
{
|
{
|
||||||
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Flush");
|
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Flush");
|
||||||
|
|
||||||
PRUint32 ret;
|
|
||||||
if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER && mState != JPEG_ERROR)
|
if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER && mState != JPEG_ERROR)
|
||||||
return this->ProcessData(nsnull, 0, &ret);
|
return this->ProcessData(nsnull, 0);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -245,57 +236,42 @@ static NS_METHOD ReadDataOut(nsIInputStream* in,
|
||||||
PRUint32 *writeCount)
|
PRUint32 *writeCount)
|
||||||
{
|
{
|
||||||
nsJPEGDecoder *decoder = static_cast<nsJPEGDecoder*>(closure);
|
nsJPEGDecoder *decoder = static_cast<nsJPEGDecoder*>(closure);
|
||||||
nsresult rv = decoder->ProcessData(fromRawSegment, count, writeCount);
|
|
||||||
if (NS_FAILED(rv)) {
|
// We always read everything
|
||||||
/* Tell imgLoader that image decoding has failed */
|
*writeCount = count;
|
||||||
|
|
||||||
|
// Process some data
|
||||||
|
nsresult rv = decoder->ProcessData(fromRawSegment, count);
|
||||||
|
|
||||||
|
// Necko's error propagation is dubious - use an explicit flag
|
||||||
|
if (NS_FAILED(rv))
|
||||||
decoder->mError = rv;
|
decoder->mError = rv;
|
||||||
*writeCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
|
|
||||||
NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *writeCount)
|
|
||||||
{
|
|
||||||
NS_ENSURE_ARG_POINTER(inStr);
|
|
||||||
NS_ENSURE_ARG_POINTER(writeCount);
|
|
||||||
|
|
||||||
/* necko doesn't propagate the errors from ReadDataOut */
|
|
||||||
nsresult rv = inStr->ReadSegments(ReadDataOut, this, count, writeCount);
|
|
||||||
if (NS_FAILED(mError)) {
|
|
||||||
/* Tell imgLoader that image decoding has failed */
|
|
||||||
rv = NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* void writeFrom (in nsIInputStream inStr, in unsigned long count); */
|
||||||
|
NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(inStr);
|
||||||
|
|
||||||
|
// Decode, watching for errors
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
PRUint32 ignored;
|
||||||
|
if (!mError)
|
||||||
|
rv = inStr->ReadSegments(ReadDataOut, this, count, &ignored);
|
||||||
|
if (mError || NS_FAILED(rv))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *writeCount)
|
nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count)
|
||||||
{
|
{
|
||||||
LOG_SCOPE_WITH_PARAM(gJPEGlog, "nsJPEGDecoder::ProcessData", "count", count);
|
LOG_SCOPE_WITH_PARAM(gJPEGlog, "nsJPEGDecoder::ProcessData", "count", count);
|
||||||
|
|
||||||
mSegment = (const JOCTET *)data;
|
mSegment = (const JOCTET *)data;
|
||||||
mSegmentLen = count;
|
mSegmentLen = count;
|
||||||
*writeCount = count;
|
|
||||||
|
|
||||||
if (data && count) {
|
|
||||||
nsresult result = mImage->AddRestoreData((char *) data, count);
|
|
||||||
|
|
||||||
if (NS_FAILED(result)) {
|
|
||||||
mState = JPEG_ERROR;
|
|
||||||
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
("} (could not add restore data)"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
(" added %u bytes to restore data",
|
|
||||||
count));
|
|
||||||
}
|
|
||||||
// else no input stream.. Flush() ?
|
|
||||||
|
|
||||||
/* Return here if there is a fatal error. */
|
/* Return here if there is a fatal error. */
|
||||||
nsresult error_code;
|
nsresult error_code;
|
||||||
|
@ -332,6 +308,16 @@ nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *
|
||||||
return NS_OK; /* I/O suspension */
|
return NS_OK; /* I/O suspension */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set Width and height, and notify that the container is ready to go. */
|
||||||
|
mImage->SetSize(mInfo.image_width, mInfo.image_height);
|
||||||
|
if (mObserver)
|
||||||
|
mObserver->OnStartContainer(nsnull, mImage);
|
||||||
|
|
||||||
|
/* If we're doing a header-only decode, we're done. */
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
/* We're doing a full decode. */
|
||||||
JOCTET *profile;
|
JOCTET *profile;
|
||||||
PRUint32 profileLength;
|
PRUint32 profileLength;
|
||||||
eCMSMode cmsMode = gfxPlatform::GetCMSMode();
|
eCMSMode cmsMode = gfxPlatform::GetCMSMode();
|
||||||
|
@ -453,25 +439,6 @@ nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *
|
||||||
/* Used to set up image size so arrays can be allocated */
|
/* Used to set up image size so arrays can be allocated */
|
||||||
jpeg_calc_output_dimensions(&mInfo);
|
jpeg_calc_output_dimensions(&mInfo);
|
||||||
|
|
||||||
mObserver->OnStartDecode(nsnull);
|
|
||||||
|
|
||||||
/* verify that the width and height of the image are the same as
|
|
||||||
* the container we're about to put things in to.
|
|
||||||
* XXX it might not matter maybe we should just resize the image.
|
|
||||||
*/
|
|
||||||
PRInt32 width, height;
|
|
||||||
mImage->GetWidth(&width);
|
|
||||||
mImage->GetHeight(&height);
|
|
||||||
if (width == 0 && height == 0) {
|
|
||||||
mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
|
|
||||||
} else if ((width != (PRInt32)mInfo.image_width) || (height != (PRInt32)mInfo.image_height)) {
|
|
||||||
mState = JPEG_ERROR;
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
|
|
||||||
|
|
||||||
mObserver->OnStartContainer(nsnull, mImage);
|
|
||||||
|
|
||||||
// Use EnsureCleanFrame so we don't create a new frame if we're being
|
// Use EnsureCleanFrame so we don't create a new frame if we're being
|
||||||
// reused for e.g. multipart/x-replace
|
// reused for e.g. multipart/x-replace
|
||||||
|
@ -489,6 +456,7 @@ nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *
|
||||||
(" JPEGDecoderAccounting: nsJPEGDecoder::ProcessData -- created image frame with %ux%u pixels",
|
(" JPEGDecoderAccounting: nsJPEGDecoder::ProcessData -- created image frame with %ux%u pixels",
|
||||||
mInfo.image_width, mInfo.image_height));
|
mInfo.image_width, mInfo.image_height));
|
||||||
|
|
||||||
|
if (mObserver)
|
||||||
mObserver->OnStartFrame(nsnull, 0);
|
mObserver->OnStartFrame(nsnull, 0);
|
||||||
mState = JPEG_START_DECOMPRESS;
|
mState = JPEG_START_DECOMPRESS;
|
||||||
}
|
}
|
||||||
|
@ -621,8 +589,6 @@ nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *
|
||||||
|
|
||||||
case JPEG_DONE:
|
case JPEG_DONE:
|
||||||
{
|
{
|
||||||
nsresult result;
|
|
||||||
|
|
||||||
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
|
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
|
||||||
|
|
||||||
/* Step 7: Finish decompression */
|
/* Step 7: Finish decompression */
|
||||||
|
@ -635,14 +601,6 @@ nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *
|
||||||
|
|
||||||
mState = JPEG_SINK_NON_JPEG_TRAILER;
|
mState = JPEG_SINK_NON_JPEG_TRAILER;
|
||||||
|
|
||||||
result = mImage->RestoreDataDone();
|
|
||||||
if (NS_FAILED (result)) {
|
|
||||||
mState = JPEG_ERROR;
|
|
||||||
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
("} (could not mark image container with RestoreDataDone)"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we're done dude */
|
/* we're done dude */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -664,6 +622,26 @@ nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsJPEGDecoder::NotifyDone(PRBool aSuccess)
|
||||||
|
{
|
||||||
|
// We should only be called once
|
||||||
|
NS_ABORT_IF_FALSE(!mNotifiedDone, "calling NotifyDone twice!");
|
||||||
|
|
||||||
|
// Notify
|
||||||
|
if (mObserver)
|
||||||
|
mObserver->OnStopFrame(nsnull, 0);
|
||||||
|
if (aSuccess)
|
||||||
|
mImage->DecodingComplete();
|
||||||
|
if (mObserver) {
|
||||||
|
mObserver->OnStopContainer(nsnull, mImage);
|
||||||
|
mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
|
||||||
|
nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark that we've been called
|
||||||
|
mNotifiedDone = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsJPEGDecoder::OutputScanlines(PRBool* suspend)
|
nsJPEGDecoder::OutputScanlines(PRBool* suspend)
|
||||||
|
@ -759,6 +737,7 @@ nsJPEGDecoder::OutputScanlines(PRBool* suspend)
|
||||||
if (top != mInfo.output_scanline) {
|
if (top != mInfo.output_scanline) {
|
||||||
nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
|
nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
|
||||||
rv = mImage->FrameUpdated(0, r);
|
rv = mImage->FrameUpdated(0, r);
|
||||||
|
if (mObserver)
|
||||||
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,17 +955,12 @@ term_source (j_decompress_ptr jd)
|
||||||
{
|
{
|
||||||
nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
|
nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
|
||||||
|
|
||||||
if (decoder->mObserver) {
|
// This function shouldn't be called if we ran into an error
|
||||||
decoder->mObserver->OnStopFrame(nsnull, 0);
|
NS_ABORT_IF_FALSE(!decoder->mError,
|
||||||
decoder->mObserver->OnStopContainer(nsnull, decoder->mImage);
|
"Calling term_source on a JPEG with mError=true!");
|
||||||
decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool multipart = PR_FALSE;
|
// Notify
|
||||||
if (decoder->mImageLoad)
|
decoder->NotifyDone(/* aSuccess = */ PR_TRUE);
|
||||||
decoder->mImageLoad->GetIsMultiPartChannel(&multipart);
|
|
||||||
if (!multipart)
|
|
||||||
decoder->mImage->DecodingComplete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -46,7 +47,6 @@
|
||||||
|
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "imgIDecoderObserver.h"
|
#include "imgIDecoderObserver.h"
|
||||||
#include "imgILoad.h"
|
|
||||||
#include "nsIInputStream.h"
|
#include "nsIInputStream.h"
|
||||||
#include "nsIPipe.h"
|
#include "nsIPipe.h"
|
||||||
#include "qcms.h"
|
#include "qcms.h"
|
||||||
|
@ -90,23 +90,24 @@ public:
|
||||||
nsJPEGDecoder();
|
nsJPEGDecoder();
|
||||||
virtual ~nsJPEGDecoder();
|
virtual ~nsJPEGDecoder();
|
||||||
|
|
||||||
nsresult ProcessData(const char *data, PRUint32 count, PRUint32 *writeCount);
|
nsresult ProcessData(const char *data, PRUint32 count);
|
||||||
|
void NotifyDone(PRBool aSuccess);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult OutputScanlines(PRBool* suspend);
|
nsresult OutputScanlines(PRBool* suspend);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
nsCOMPtr<imgILoad> mImageLoad;
|
|
||||||
|
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver;
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
|
||||||
|
PRUint32 mFlags;
|
||||||
PRUint8 *mImageData;
|
PRUint8 *mImageData;
|
||||||
|
|
||||||
struct jpeg_decompress_struct mInfo;
|
struct jpeg_decompress_struct mInfo;
|
||||||
struct jpeg_source_mgr mSourceMgr;
|
struct jpeg_source_mgr mSourceMgr;
|
||||||
decoder_error_mgr mErr;
|
decoder_error_mgr mErr;
|
||||||
jstate mState;
|
jstate mState;
|
||||||
nsresult mError;
|
PRBool mError;
|
||||||
|
|
||||||
PRUint32 mBytesToSkip;
|
PRUint32 mBytesToSkip;
|
||||||
|
|
||||||
|
@ -125,6 +126,7 @@ public:
|
||||||
qcms_transform *mTransform;
|
qcms_transform *mTransform;
|
||||||
|
|
||||||
PRPackedBool mReading;
|
PRPackedBool mReading;
|
||||||
|
PRPackedBool mNotifiedDone;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsJPEGDecoder_h__
|
#endif // nsJPEGDecoder_h__
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* Stuart Parmenter <stuart@mozilla.com>
|
* Stuart Parmenter <stuart@mozilla.com>
|
||||||
* Andrew Smith
|
* Andrew Smith
|
||||||
* Federico Mena-Quintero <federico@novell.com>
|
* Federico Mena-Quintero <federico@novell.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -71,13 +72,29 @@ static PRLogModuleInfo *gPNGLog = PR_NewLogModule("PNGDecoder");
|
||||||
static PRLogModuleInfo *gPNGDecoderAccountingLog = PR_NewLogModule("PNGDecoderAccounting");
|
static PRLogModuleInfo *gPNGDecoderAccountingLog = PR_NewLogModule("PNGDecoderAccounting");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* limit image dimensions (bug #251381) */
|
||||||
|
#define MOZ_PNG_MAX_DIMENSION 1000000L
|
||||||
|
|
||||||
|
// For header-only decodes
|
||||||
|
#define WIDTH_OFFSET 16
|
||||||
|
#define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
|
||||||
|
#define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
|
||||||
|
|
||||||
|
// This is defined in the PNG spec as an invariant. We use it to
|
||||||
|
// do manual validation without libpng.
|
||||||
|
static const PRUint8 pngSignatureBytes[] =
|
||||||
|
{ 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(nsPNGDecoder, imgIDecoder)
|
NS_IMPL_ISUPPORTS1(nsPNGDecoder, imgIDecoder)
|
||||||
|
|
||||||
nsPNGDecoder::nsPNGDecoder() :
|
nsPNGDecoder::nsPNGDecoder() :
|
||||||
mPNG(nsnull), mInfo(nsnull),
|
mPNG(nsnull), mInfo(nsnull),
|
||||||
mCMSLine(nsnull), interlacebuf(nsnull),
|
mCMSLine(nsnull), interlacebuf(nsnull),
|
||||||
mInProfile(nsnull), mTransform(nsnull),
|
mInProfile(nsnull), mTransform(nsnull),
|
||||||
mChannels(0), mError(PR_FALSE), mFrameIsHidden(PR_FALSE)
|
mHeaderBuf(nsnull), mHeaderBytesRead(0),
|
||||||
|
mChannels(0), mError(PR_FALSE), mFrameIsHidden(PR_FALSE),
|
||||||
|
mNotifiedDone(PR_FALSE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +111,8 @@ nsPNGDecoder::~nsPNGDecoder()
|
||||||
if (mTransform)
|
if (mTransform)
|
||||||
qcms_transform_release(mTransform);
|
qcms_transform_release(mTransform);
|
||||||
}
|
}
|
||||||
|
if (mHeaderBuf)
|
||||||
|
nsMemory::Free(mHeaderBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateFrame() is used for both simple and animated images
|
// CreateFrame() is used for both simple and animated images
|
||||||
|
@ -191,6 +210,7 @@ void nsPNGDecoder::EndImageFrame()
|
||||||
}
|
}
|
||||||
PRUint32 curFrame;
|
PRUint32 curFrame;
|
||||||
mImage->GetCurrentFrameIndex(&curFrame);
|
mImage->GetCurrentFrameIndex(&curFrame);
|
||||||
|
if (mObserver)
|
||||||
mObserver->OnDataAvailable(nsnull, curFrame == numFrames - 1, &mFrameRect);
|
mObserver->OnDataAvailable(nsnull, curFrame == numFrames - 1, &mFrameRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,8 +222,12 @@ void nsPNGDecoder::EndImageFrame()
|
||||||
|
|
||||||
/** imgIDecoder methods **/
|
/** imgIDecoder methods **/
|
||||||
|
|
||||||
/* void init (in imgILoad aLoad); */
|
/* void init (in imgIContainer aImage,
|
||||||
NS_IMETHODIMP nsPNGDecoder::Init(imgILoad *aLoad)
|
imgIDecoderObserver aObserver,
|
||||||
|
unsigned long aFlags); */
|
||||||
|
NS_IMETHODIMP nsPNGDecoder::Init(imgIContainer *aImage,
|
||||||
|
imgIDecoderObserver *aObserver,
|
||||||
|
PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
||||||
static png_byte color_chunks[]=
|
static png_byte color_chunks[]=
|
||||||
|
@ -224,10 +248,23 @@ NS_IMETHODIMP nsPNGDecoder::Init(imgILoad *aLoad)
|
||||||
122, 84, 88, 116, '\0'}; /* zTXt */
|
122, 84, 88, 116, '\0'}; /* zTXt */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mImageLoad = aLoad;
|
mImage = aImage;
|
||||||
mObserver = do_QueryInterface(aLoad); // we're holding 2 strong refs to the request.
|
mObserver = aObserver;
|
||||||
|
mFlags = aFlags;
|
||||||
|
|
||||||
/* do png init stuff */
|
// Fire OnStartDecode at init time to support bug 512435
|
||||||
|
if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
|
||||||
|
mObserver->OnStartDecode(nsnull);
|
||||||
|
|
||||||
|
// For header-only decodes, we only need a small buffer
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) {
|
||||||
|
mHeaderBuf = (PRUint8 *)nsMemory::Alloc(BYTES_NEEDED_FOR_DIMENSIONS);
|
||||||
|
if (!mHeaderBuf)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For full decodes, do png init stuff */
|
||||||
|
|
||||||
/* Initialize the container's source image header. */
|
/* Initialize the container's source image header. */
|
||||||
/* Always decode to 24 bit pixdepth */
|
/* Always decode to 24 bit pixdepth */
|
||||||
|
@ -258,48 +295,23 @@ NS_IMETHODIMP nsPNGDecoder::Init(imgILoad *aLoad)
|
||||||
info_callback, row_callback, end_callback);
|
info_callback, row_callback, end_callback);
|
||||||
|
|
||||||
|
|
||||||
/* The image container may already exist if it is reloading itself from us.
|
|
||||||
* Check that it has the same width/height; otherwise create a new container.
|
|
||||||
*/
|
|
||||||
mImageLoad->GetImage(getter_AddRefs(mImage));
|
|
||||||
if (!mImage) {
|
|
||||||
mImage = do_CreateInstance("@mozilla.org/image/container;2");
|
|
||||||
if (!mImage)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
mImageLoad->SetImage(mImage);
|
|
||||||
if (NS_FAILED(mImage->SetDiscardable("image/png"))) {
|
|
||||||
PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
("PNGDecoderAccounting: info_callback(): failed to set image container %p as discardable",
|
|
||||||
mImage.get()));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* void close (); */
|
/* void close (); */
|
||||||
NS_IMETHODIMP nsPNGDecoder::Close()
|
NS_IMETHODIMP nsPNGDecoder::Close(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
if (mPNG)
|
if (mPNG)
|
||||||
png_destroy_read_struct(&mPNG, mInfo ? &mInfo : NULL, NULL);
|
png_destroy_read_struct(&mPNG, mInfo ? &mInfo : NULL, NULL);
|
||||||
|
|
||||||
if (mImage) { // mImage could be null in the case of an error
|
// If we're a full/success decode but haven't sent stop notifications yet,
|
||||||
nsresult result = mImage->RestoreDataDone();
|
// we didn't get all the data we needed. Send error notifications.
|
||||||
if (NS_FAILED(result)) {
|
if (!(aFlags & CLOSE_FLAG_DONTNOTIFY) &&
|
||||||
PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
|
!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
|
||||||
("PNGDecoderAccounting: nsPNGDecoder::Close(): failure in RestoreDataDone() for image container %p",
|
!mNotifiedDone)
|
||||||
mImage.get()));
|
NotifyDone(/* aSuccess = */ PR_FALSE);
|
||||||
|
|
||||||
mError = PR_TRUE;
|
mImage = nsnull;
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
("PNGDecoderAccounting: nsPNGDecoder::Close(): image container %p is now with RestoreDataDone",
|
|
||||||
mImage.get()));
|
|
||||||
}
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,6 +321,99 @@ NS_IMETHODIMP nsPNGDecoder::Flush()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We make this a method to get the benefit of the 'this' parameter
|
||||||
|
NS_METHOD
|
||||||
|
nsPNGDecoder::ProcessData(unsigned char* aBuffer, PRUint32 aCount)
|
||||||
|
{
|
||||||
|
// We use gotos, so we need to declare variables here
|
||||||
|
nsresult rv;
|
||||||
|
PRUint32 width = 0;
|
||||||
|
PRUint32 height = 0;
|
||||||
|
|
||||||
|
// No forgiveness if we previously hit an error
|
||||||
|
if (mError)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// If we only want width/height, we don't need to go through libpng
|
||||||
|
if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) {
|
||||||
|
|
||||||
|
// Are we done?
|
||||||
|
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// Read data into our header buffer
|
||||||
|
PRUint32 bytesToRead = PR_MIN(aCount, BYTES_NEEDED_FOR_DIMENSIONS - mHeaderBytesRead);
|
||||||
|
memcpy(mHeaderBuf + mHeaderBytesRead, aBuffer, bytesToRead);
|
||||||
|
mHeaderBytesRead += bytesToRead;
|
||||||
|
|
||||||
|
// If we're done now, verify the data and set up the container
|
||||||
|
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
|
||||||
|
|
||||||
|
// Check that the signature bytes are right
|
||||||
|
if (memcmp(mHeaderBuf, pngSignatureBytes, sizeof(pngSignatureBytes)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Grab the width and height, accounting for endianness (thanks libpng!)
|
||||||
|
width = png_get_uint_32(mHeaderBuf + WIDTH_OFFSET);
|
||||||
|
height = png_get_uint_32(mHeaderBuf + HEIGHT_OFFSET);
|
||||||
|
|
||||||
|
// Too big?
|
||||||
|
if ((width > MOZ_PNG_MAX_DIMENSION) || (height > MOZ_PNG_MAX_DIMENSION))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Set the size
|
||||||
|
rv = mImage->SetSize(width, height);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Notify the observer that the container is up
|
||||||
|
if (mObserver)
|
||||||
|
mObserver->OnStartContainer(nsnull, mImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we're doing a standard decode
|
||||||
|
else {
|
||||||
|
|
||||||
|
// libpng uses setjmp/longjmp for error handling - set the buffer
|
||||||
|
if (setjmp(mPNG->jmpbuf)) {
|
||||||
|
png_destroy_read_struct(&mPNG, &mInfo, NULL);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the data off to libpng
|
||||||
|
png_process_data(mPNG, mInfo, aBuffer, aCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// Consolidate error handling
|
||||||
|
error:
|
||||||
|
mError = PR_TRUE;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsPNGDecoder::NotifyDone(PRBool aSuccess)
|
||||||
|
{
|
||||||
|
// We should only be called once
|
||||||
|
NS_ABORT_IF_FALSE(!mNotifiedDone, "Calling NotifyDone twice!");
|
||||||
|
|
||||||
|
// Notify
|
||||||
|
if (!mFrameIsHidden)
|
||||||
|
EndImageFrame();
|
||||||
|
if (aSuccess)
|
||||||
|
mImage->DecodingComplete();
|
||||||
|
if (mObserver) {
|
||||||
|
mObserver->OnStopContainer(nsnull, mImage);
|
||||||
|
mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
|
||||||
|
nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark that we've been called
|
||||||
|
mNotifiedDone = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static NS_METHOD ReadDataOut(nsIInputStream* in,
|
static NS_METHOD ReadDataOut(nsIInputStream* in,
|
||||||
void* closure,
|
void* closure,
|
||||||
|
@ -317,60 +422,32 @@ static NS_METHOD ReadDataOut(nsIInputStream* in,
|
||||||
PRUint32 count,
|
PRUint32 count,
|
||||||
PRUint32 *writeCount)
|
PRUint32 *writeCount)
|
||||||
{
|
{
|
||||||
|
// Grab the decoder
|
||||||
|
NS_ENSURE_ARG_POINTER(closure);
|
||||||
nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(closure);
|
nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(closure);
|
||||||
|
|
||||||
if (decoder->mError) {
|
// We always read everything
|
||||||
*writeCount = 0;
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we force to add even erroneous data to restore halfway frame information
|
|
||||||
// later - bug 441563
|
|
||||||
nsresult result = decoder->mImage->AddRestoreData(const_cast<char *>(fromRawSegment), count);
|
|
||||||
if (NS_FAILED (result)) {
|
|
||||||
PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
("PNGDecoderAccounting: ReadDataOut(): failed to add restore data to image container %p",
|
|
||||||
decoder->mImage.get()));
|
|
||||||
|
|
||||||
decoder->mError = PR_TRUE;
|
|
||||||
*writeCount = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
decoder->mError = PR_TRUE;
|
|
||||||
*writeCount = 0;
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
png_process_data(decoder->mPNG, decoder->mInfo,
|
|
||||||
reinterpret_cast<unsigned char *>(const_cast<char *>(fromRawSegment)), count);
|
|
||||||
|
|
||||||
PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
|
|
||||||
("PNGDecoderAccounting: ReadDataOut(): Added restore data to image container %p",
|
|
||||||
decoder->mImage.get()));
|
|
||||||
|
|
||||||
*writeCount = count;
|
*writeCount = count;
|
||||||
return NS_OK;
|
|
||||||
|
// Twiddle the types, then process the data
|
||||||
|
char *unConst = const_cast<char *>(fromRawSegment);
|
||||||
|
unsigned char *buffer = reinterpret_cast<unsigned char *>(unConst);
|
||||||
|
return decoder->ProcessData(buffer, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
|
/* writeFrom (in nsIInputStream inStr, in unsigned long count); */
|
||||||
NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
|
NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(inStr, "Got a null input stream!");
|
NS_ASSERTION(inStr, "Got a null input stream!");
|
||||||
|
|
||||||
nsresult rv;
|
// Decode, watching for errors
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
PRUint32 ignored;
|
||||||
if (!mError)
|
if (!mError)
|
||||||
rv = inStr->ReadSegments(ReadDataOut, this, count, _retval);
|
rv = inStr->ReadSegments(ReadDataOut, this, count, &ignored);
|
||||||
|
if (mError || NS_FAILED(rv))
|
||||||
if (mError) {
|
|
||||||
*_retval = 0;
|
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -505,16 +582,23 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
int num_trans = 0;
|
int num_trans = 0;
|
||||||
|
|
||||||
nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
/* always decode to 24-bit RGB or 32-bit RGBA */
|
/* always decode to 24-bit RGB or 32-bit RGBA */
|
||||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
||||||
&interlace_type, &compression_type, &filter_type);
|
&interlace_type, &compression_type, &filter_type);
|
||||||
|
|
||||||
/* limit image dimensions (bug #251381) */
|
/* Are we too big? */
|
||||||
#define MOZ_PNG_MAX_DIMENSION 1000000L
|
|
||||||
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION)
|
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION)
|
||||||
longjmp(decoder->mPNG->jmpbuf, 1);
|
longjmp(decoder->mPNG->jmpbuf, 1);
|
||||||
#undef MOZ_PNG_MAX_DIMENSION
|
|
||||||
|
// Set the size and notify that the container is set up
|
||||||
|
rv = decoder->mImage->SetSize(width, height);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_UNEXPECTED
|
||||||
|
}
|
||||||
|
if (decoder->mObserver)
|
||||||
|
decoder->mObserver->OnStartContainer(nsnull, decoder->mImage);
|
||||||
|
|
||||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
png_set_expand(png_ptr);
|
png_set_expand(png_ptr);
|
||||||
|
@ -616,25 +700,6 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoder->mObserver)
|
|
||||||
decoder->mObserver->OnStartDecode(nsnull);
|
|
||||||
|
|
||||||
/* The image container may already exist if it is reloading itself from us.
|
|
||||||
* Check that it has the same width/height; otherwise create a new container.
|
|
||||||
*/
|
|
||||||
PRInt32 containerWidth, containerHeight;
|
|
||||||
decoder->mImage->GetWidth(&containerWidth);
|
|
||||||
decoder->mImage->GetHeight(&containerHeight);
|
|
||||||
if (containerWidth == 0 && containerHeight == 0) {
|
|
||||||
// the image hasn't been inited yet
|
|
||||||
decoder->mImage->Init(width, height, decoder->mObserver);
|
|
||||||
} else if (containerWidth != PRInt32(width) || containerHeight != PRInt32(height)) {
|
|
||||||
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_UNEXPECTED
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decoder->mObserver)
|
|
||||||
decoder->mObserver->OnStartContainer(nsnull, decoder->mImage);
|
|
||||||
|
|
||||||
if (channels == 1 || channels == 3)
|
if (channels == 1 || channels == 3)
|
||||||
decoder->format = gfxASurface::ImageFormatRGB24;
|
decoder->format = gfxASurface::ImageFormatRGB24;
|
||||||
else if (channels == 2 || channels == 4)
|
else if (channels == 2 || channels == 4)
|
||||||
|
@ -654,9 +719,10 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
PRUint32 bpp[] = { 0, 3, 4, 3, 4 };
|
PRUint32 bpp[] = { 0, 3, 4, 3, 4 };
|
||||||
decoder->mCMSLine =
|
decoder->mCMSLine =
|
||||||
(PRUint8 *)nsMemory::Alloc(bpp[channels] * width);
|
(PRUint8 *)nsMemory::Alloc(bpp[channels] * width);
|
||||||
if (!decoder->mCMSLine)
|
if (!decoder->mCMSLine) {
|
||||||
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (interlace_type == PNG_INTERLACE_ADAM7) {
|
if (interlace_type == PNG_INTERLACE_ADAM7) {
|
||||||
if (height < PR_INT32_MAX / (width * channels))
|
if (height < PR_INT32_MAX / (width * channels))
|
||||||
|
@ -800,6 +866,7 @@ row_callback(png_structp png_ptr, png_bytep new_row,
|
||||||
}
|
}
|
||||||
PRUint32 curFrame;
|
PRUint32 curFrame;
|
||||||
decoder->mImage->GetCurrentFrameIndex(&curFrame);
|
decoder->mImage->GetCurrentFrameIndex(&curFrame);
|
||||||
|
if (decoder->mObserver)
|
||||||
decoder->mObserver->OnDataAvailable(nsnull, curFrame == numFrames - 1, &r);
|
decoder->mObserver->OnDataAvailable(nsnull, curFrame == numFrames - 1, &r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,20 +912,16 @@ end_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
|
|
||||||
nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
||||||
|
|
||||||
|
// We shouldn't get here if we've hit an error
|
||||||
|
NS_ABORT_IF_FALSE(!decoder->mError, "Finishing up PNG but hit error!");
|
||||||
|
|
||||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
|
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
|
||||||
PRInt32 num_plays = png_get_num_plays(png_ptr, info_ptr);
|
PRInt32 num_plays = png_get_num_plays(png_ptr, info_ptr);
|
||||||
decoder->mImage->SetLoopCount(num_plays - 1);
|
decoder->mImage->SetLoopCount(num_plays - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decoder->mFrameIsHidden)
|
// Send final notifications
|
||||||
decoder->EndImageFrame();
|
decoder->NotifyDone(/* aSuccess = */ PR_TRUE);
|
||||||
|
|
||||||
decoder->mImage->DecodingComplete();
|
|
||||||
|
|
||||||
if (decoder->mObserver) {
|
|
||||||
decoder->mObserver->OnStopContainer(nsnull, decoder->mImage);
|
|
||||||
decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -44,7 +45,6 @@
|
||||||
|
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "imgIDecoderObserver.h"
|
#include "imgIDecoderObserver.h"
|
||||||
#include "imgILoad.h"
|
|
||||||
#include "gfxASurface.h"
|
#include "gfxASurface.h"
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -76,11 +76,13 @@ public:
|
||||||
void SetAnimFrameInfo();
|
void SetAnimFrameInfo();
|
||||||
|
|
||||||
void EndImageFrame();
|
void EndImageFrame();
|
||||||
|
NS_METHOD ProcessData(unsigned char* aBuffer, PRUint32 aCount);
|
||||||
|
void NotifyDone(PRBool aSuccess);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
nsCOMPtr<imgILoad> mImageLoad;
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
|
PRUint32 mFlags;
|
||||||
|
|
||||||
png_structp mPNG;
|
png_structp mPNG;
|
||||||
png_infop mInfo;
|
png_infop mInfo;
|
||||||
|
@ -92,10 +94,16 @@ public:
|
||||||
qcms_transform *mTransform;
|
qcms_transform *mTransform;
|
||||||
|
|
||||||
gfxASurface::gfxImageFormat format;
|
gfxASurface::gfxImageFormat format;
|
||||||
|
|
||||||
|
// For header-only decodes
|
||||||
|
PRUint8 *mHeaderBuf;
|
||||||
|
PRUint32 mHeaderBytesRead;
|
||||||
|
|
||||||
PRUint8 mChannels;
|
PRUint8 mChannels;
|
||||||
PRPackedBool mError;
|
PRPackedBool mError;
|
||||||
PRPackedBool mFrameHasNoAlpha;
|
PRPackedBool mFrameHasNoAlpha;
|
||||||
PRPackedBool mFrameIsHidden;
|
PRPackedBool mFrameIsHidden;
|
||||||
|
PRPackedBool mNotifiedDone;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsPNGDecoder_h__
|
#endif // nsPNGDecoder_h__
|
||||||
|
|
|
@ -54,7 +54,6 @@ XPIDLSRCS = \
|
||||||
imgIDecoder.idl \
|
imgIDecoder.idl \
|
||||||
imgIDecoderObserver.idl \
|
imgIDecoderObserver.idl \
|
||||||
imgIEncoder.idl \
|
imgIEncoder.idl \
|
||||||
imgILoad.idl \
|
|
||||||
imgILoader.idl \
|
imgILoader.idl \
|
||||||
imgIRequest.idl \
|
imgIRequest.idl \
|
||||||
imgITools.idl \
|
imgITools.idl \
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
* Federico Mena-Quintero <federico@novell.com>
|
* Federico Mena-Quintero <federico@novell.com>
|
||||||
* Joe Drew <joe@drew.ca>
|
* Joe Drew <joe@drew.ca>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -41,7 +42,7 @@
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface imgIContainerObserver;
|
interface imgIDecoderObserver;
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
#include "gfxImageSurface.h"
|
#include "gfxImageSurface.h"
|
||||||
|
@ -70,7 +71,7 @@ native gfxGraphicsFilter(gfxPattern::GraphicsFilter);
|
||||||
*
|
*
|
||||||
* Internally, imgIContainer also manages animation of images.
|
* Internally, imgIContainer also manages animation of images.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(1bcf7a25-1356-47a8-bf80-e284989ea38f)]
|
[scriptable, uuid(74c63935-b54f-43a4-9449-2e9c815e3bef)]
|
||||||
interface imgIContainer : nsISupports
|
interface imgIContainer : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -95,25 +96,64 @@ interface imgIContainer : nsISupports
|
||||||
readonly attribute boolean currentFrameIsOpaque;
|
readonly attribute boolean currentFrameIsOpaque;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a surface for the current frame. This may be a platform-native,
|
* Flags for imgIContainer operations.
|
||||||
* optimized frame, so you cannot inspect its pixel data.
|
*
|
||||||
|
* Meanings:
|
||||||
|
*
|
||||||
|
* FLAG_NONE: Lack of flags
|
||||||
|
*
|
||||||
|
* FLAG_SYNC_DECODE: Forces synchronous/non-progressive decode of all
|
||||||
|
* available data before the call returns.
|
||||||
*/
|
*/
|
||||||
[noscript] readonly attribute gfxASurface currentFrame;
|
|
||||||
|
const long FLAG_NONE = 0x0;
|
||||||
|
const long FLAG_SYNC_DECODE = 0x1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return a new copy of the current frame that you can write to
|
* Constants for specifying various "special" frames.
|
||||||
* and otherwise inspect the pixels of.
|
*
|
||||||
|
* FRAME_FIRST: The first frame
|
||||||
|
* FRAME_CURRENT: The current frame
|
||||||
|
*
|
||||||
|
* FRAME_MAX_VALUE should be set to the value of the maximum constant above,
|
||||||
|
* as it is used for ensuring that a valid value was passed in.
|
||||||
*/
|
*/
|
||||||
[noscript] gfxImageSurface copyCurrentFrame();
|
const unsigned long FRAME_FIRST = 0;
|
||||||
|
const unsigned long FRAME_CURRENT = 1;
|
||||||
|
const unsigned long FRAME_MAX_VALUE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a surface for the given frame. This may be a platform-native,
|
||||||
|
* optimized surface, so you cannot inspect its pixel data.
|
||||||
|
*
|
||||||
|
* @param aWhichFrame Frame specifier of the FRAME_* variety.
|
||||||
|
* @param aFlags Flags of the FLAG_* variety
|
||||||
|
*/
|
||||||
|
[noscript] gfxASurface getFrame(in PRUint32 aWhichFrame,
|
||||||
|
in PRUint32 aFlags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a new copy of the given frame that you can write to
|
||||||
|
* and otherwise inspect the pixels of.
|
||||||
|
*
|
||||||
|
* @param aWhichFrame Frame specifier of the FRAME_* variety.
|
||||||
|
* @param aFlags Flags of the FLAG_* variety
|
||||||
|
*/
|
||||||
|
[noscript] gfxImageSurface copyFrame(in PRUint32 aWhichFrame,
|
||||||
|
in PRUint32 aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new imgContainer that contains only a single frame, which itself
|
* Create a new imgContainer that contains only a single frame, which itself
|
||||||
* contains a subregion of the current frame.
|
* contains a subregion of the given frame.
|
||||||
*
|
*
|
||||||
|
* @param aWhichFrame Frame specifier of the FRAME_* variety.
|
||||||
* @param aRect the area of the current frame to be duplicated in the
|
* @param aRect the area of the current frame to be duplicated in the
|
||||||
* returned imgContainer's frame.
|
* returned imgContainer's frame.
|
||||||
|
* @param aFlags Flags of the FLAG_* variety
|
||||||
*/
|
*/
|
||||||
[noscript] imgIContainer extractCurrentFrame([const] in nsIntRect aRect);
|
[noscript] imgIContainer extractFrame(in PRUint32 aWhichFrame,
|
||||||
|
[const] in nsIntRect aRect,
|
||||||
|
in PRUint32 aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the current frame on to the context specified.
|
* Draw the current frame on to the context specified.
|
||||||
|
@ -126,26 +166,76 @@ interface imgIContainer : nsISupports
|
||||||
* automatically tiled as necessary.
|
* automatically tiled as necessary.
|
||||||
* @param aSubimage The area of the image, in pixels, that we are allowed to
|
* @param aSubimage The area of the image, in pixels, that we are allowed to
|
||||||
* sample from.
|
* sample from.
|
||||||
|
* @param aFlags Flags of the FLAG_* variety
|
||||||
*/
|
*/
|
||||||
[noscript] void draw(in gfxContext aContext, in gfxGraphicsFilter aFilter,
|
[noscript] void draw(in gfxContext aContext, in gfxGraphicsFilter aFilter,
|
||||||
in gfxMatrix aUserSpaceToImageSpace, in gfxRect aFill,
|
in gfxMatrix aUserSpaceToImageSpace, in gfxRect aFill,
|
||||||
in nsIntRect aSubimage);
|
in nsIntRect aSubimage, in PRUint32 aFlags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensures that an image is decoding. Calling this function guarantees that
|
||||||
|
* the image will at some point fire off decode notifications. Calling draw(),
|
||||||
|
* getFrame(), copyFrame(), or extractCurrentFrame() triggers the same
|
||||||
|
* mechanism internally. Thus, if you want to be sure that the image will be
|
||||||
|
* decoded but don't want to access it until then, you must call
|
||||||
|
* requestDecode().
|
||||||
|
*/
|
||||||
|
void requestDecode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the lock count on the image. An image will not be discarded
|
||||||
|
* as long as the lock count is nonzero. Note that it is still possible for
|
||||||
|
* the image to be undecoded if decode-on-draw is enabled and the image
|
||||||
|
* was never drawn.
|
||||||
|
*
|
||||||
|
* Upon instantiation images have a lock count of zero.
|
||||||
|
*/
|
||||||
|
void lockImage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decreases the lock count on the image. If the lock count drops to zero,
|
||||||
|
* the image is allowed to discard its frame data to save memory.
|
||||||
|
*
|
||||||
|
* Upon instantiation images have a lock count of zero. It is an error to
|
||||||
|
* call this method without first having made a matching lockImage() call.
|
||||||
|
* In other words, the lock count is not allowed to be negative.
|
||||||
|
*/
|
||||||
|
void unlockImage();
|
||||||
|
|
||||||
/************ Internal libpr0n use only below here. *****************/
|
/************ Internal libpr0n use only below here. *****************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new \a aWidth x \a aHeight sized image container.
|
* Flags for imgIContainer initialization.
|
||||||
*
|
*
|
||||||
* @param aWidth The width of the container in which all the
|
* Meanings:
|
||||||
* frames will fit.
|
*
|
||||||
* @param aHeight The height of the container in which all the
|
* INIT_FLAG_NONE: Lack of flags
|
||||||
* frames will fit.
|
*
|
||||||
* @param aObserver Observer to send animation notifications to.
|
* INIT_FLAG_DISCARDABLE: The container should be discardable
|
||||||
|
*
|
||||||
|
* INIT_FLAG_DECODE_ON_DRAW: The container should decode on draw rather than
|
||||||
|
* decoding on load.
|
||||||
|
*
|
||||||
|
* INIT_FLAG_MULTIPART: The container will be used to display a stream of
|
||||||
|
* images in a multipart channel. If this flag is set, INIT_FLAG_DISCARDABLE
|
||||||
|
* and INIT_FLAG_DECODE_ON_DRAW must not be set.
|
||||||
*/
|
*/
|
||||||
void init(in PRInt32 aWidth,
|
|
||||||
in PRInt32 aHeight,
|
const long INIT_FLAG_NONE = 0x0;
|
||||||
in imgIContainerObserver aObserver);
|
const long INIT_FLAG_DISCARDABLE = 0x1;
|
||||||
|
const long INIT_FLAG_DECODE_ON_DRAW = 0x2;
|
||||||
|
const long INIT_FLAG_MULTIPART = 0x4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new image container.
|
||||||
|
*
|
||||||
|
* @param aObserver Observer to send decoder and animation notifications to.
|
||||||
|
* @param aMimeType The mimetype of the image.
|
||||||
|
* @param aFlags Initialization flags of the INIT_FLAG_* variety.
|
||||||
|
*/
|
||||||
|
void init(in imgIDecoderObserver aObserver,
|
||||||
|
in string aMimeType,
|
||||||
|
in PRUint32 aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Disposal" method indicates how the image should be handled before the
|
* "Disposal" method indicates how the image should be handled before the
|
||||||
|
@ -201,19 +291,22 @@ interface imgIContainer : nsISupports
|
||||||
readonly attribute unsigned long numFrames;
|
readonly attribute unsigned long numFrames;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size, in bytes, of a particular frame's image data.
|
* The size, in bytes, occupied by the significant data portions of the image.
|
||||||
|
* This includes both compressed source data and decoded frames.
|
||||||
*/
|
*/
|
||||||
unsigned long getFrameImageDataLength(in unsigned long framenumber);
|
readonly attribute unsigned long dataSize;
|
||||||
|
|
||||||
void getFrameColormap(in unsigned long framenumber,
|
|
||||||
[array, size_is(paletteLength)] out PRUint32 paletteData,
|
|
||||||
out unsigned long paletteLength);
|
|
||||||
|
|
||||||
void setFrameDisposalMethod(in unsigned long framenumber, in PRInt32 aDisposalMethod);
|
void setFrameDisposalMethod(in unsigned long framenumber, in PRInt32 aDisposalMethod);
|
||||||
void setFrameBlendMethod(in unsigned long framenumber, in PRInt32 aBlendMethod);
|
void setFrameBlendMethod(in unsigned long framenumber, in PRInt32 aBlendMethod);
|
||||||
void setFrameTimeout(in unsigned long framenumber, in PRInt32 aTimeout);
|
void setFrameTimeout(in unsigned long framenumber, in PRInt32 aTimeout);
|
||||||
void setFrameHasNoAlpha(in unsigned long framenumber);
|
void setFrameHasNoAlpha(in unsigned long framenumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the size of the container. This should only be called by the decoder. This function may be called multiple
|
||||||
|
* times, but will throw an error if subsequent calls do not match the first.
|
||||||
|
*/
|
||||||
|
[noscript] void setSize(in long aWidth, in long aHeight);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create or re-use a frame at index aFrameNum. It is an error to call this with aFrameNum not in the range [0, numFrames].
|
* Create or re-use a frame at index aFrameNum. It is an error to call this with aFrameNum not in the range [0, numFrames].
|
||||||
*/
|
*/
|
||||||
|
@ -249,9 +342,18 @@ interface imgIContainer : nsISupports
|
||||||
*/
|
*/
|
||||||
attribute long loopCount;
|
attribute long loopCount;
|
||||||
|
|
||||||
/* Methods to discard uncompressed images and restore them again */
|
/* Add compressed source data to the imgContainer.
|
||||||
[noscript] void setDiscardable(in string aMimeType);
|
*
|
||||||
[noscript] void addRestoreData([array, size_is(aCount), const] in char data,
|
* The decoder will use this data, either immediately or at draw time, do
|
||||||
|
* decode the image.
|
||||||
|
*/
|
||||||
|
[noscript] void addSourceData([array, size_is(aCount), const] in char data,
|
||||||
in unsigned long aCount);
|
in unsigned long aCount);
|
||||||
[noscript] void restoreDataDone();
|
|
||||||
|
/* Called after the all the source data has been added with addSourceData. */
|
||||||
|
[noscript] void sourceDataComplete();
|
||||||
|
|
||||||
|
/* Called for multipart images when there's a new source image to add. */
|
||||||
|
[noscript] void newSourceData();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -40,7 +41,8 @@
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface nsIInputStream;
|
interface nsIInputStream;
|
||||||
interface imgILoad;
|
interface imgIContainer;
|
||||||
|
interface imgIDecoderObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* imgIDecoder interface
|
* imgIDecoder interface
|
||||||
|
@ -49,24 +51,47 @@ interface imgILoad;
|
||||||
* @version 0.2
|
* @version 0.2
|
||||||
* @see imagelib2
|
* @see imagelib2
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(9eebf43a-1dd1-11b2-953e-f1782f4cbad3)]
|
[scriptable, uuid(139c6f97-cd2f-4a4f-890d-8d9f4a693682)]
|
||||||
interface imgIDecoder : nsISupports
|
interface imgIDecoder : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initialize an image decoder.
|
* Bits that can be passed to the decoder to affect decoding.
|
||||||
* @param aRequest the request that owns the decoder.
|
* @name decodeflags
|
||||||
*
|
*
|
||||||
* @note The decode should QI \a aLoad to an imgIDecoderObserver
|
* Meanings:
|
||||||
* and should send decoder notifications to the request.
|
*
|
||||||
* The decoder should always pass NULL as the first two parameters to
|
* DECODER_FLAG_NONE: No flags
|
||||||
* all of the imgIDecoderObserver APIs.
|
*
|
||||||
|
* DECODER_FLAG_HEADERONLY: Read basic data from the image in order to
|
||||||
|
* set up the image container, but don't read any actual image data.
|
||||||
*/
|
*/
|
||||||
void init(in imgILoad aLoad);
|
const long DECODER_FLAG_NONE = 0x0;
|
||||||
|
const long DECODER_FLAG_HEADERONLY = 0x1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an image decoder.
|
||||||
|
* @param aContainer The image container to decode to.
|
||||||
|
* @param aObserver The observer for decode notification events.
|
||||||
|
* @param aFlags Flags for the decoder
|
||||||
|
*
|
||||||
|
* @note The decoder should always pass NULL as the
|
||||||
|
* first two parameters to all of the imgIDecoderObserver APIs.
|
||||||
|
*/
|
||||||
|
void init(in imgIContainer aImage, in imgIDecoderObserver aObserver,
|
||||||
|
in unsigned long aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the stream.
|
* Closes the stream.
|
||||||
|
* @param aFlags Close flags of the CLOSE_FLAG_* Variety
|
||||||
|
*
|
||||||
|
* Resources are always freed with this call. If notifications are sent,
|
||||||
|
* OnStopDecode is guaranteed to be called if it hasn't been called already.
|
||||||
|
*
|
||||||
|
* CLOSE_FLAG_DONTNOTIFY - Don't send any observer notifications, and don't
|
||||||
|
* call imgIContainer::decodingComplete().
|
||||||
*/
|
*/
|
||||||
void close();
|
const long CLOSE_FLAG_DONTNOTIFY = 0x01;
|
||||||
|
void close(in PRUint32 aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flushes the stream.
|
* Flushes the stream.
|
||||||
|
@ -75,6 +100,16 @@ interface imgIDecoder : nsISupports
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes data into the stream from an input stream.
|
* Writes data into the stream from an input stream.
|
||||||
|
*
|
||||||
|
* For Header-Only decodes, OnStartContainer is the only notification
|
||||||
|
* fired.
|
||||||
|
*
|
||||||
|
* If a decoding error occurs, an internal flag is set and an error is
|
||||||
|
* returned. Each subsequent call to writeFrom will fail immediately
|
||||||
|
* for the lifetime of the decoder. Shutdown notifications of the OnStopX
|
||||||
|
* variety, as well as DecodingComplete(), are guaranteed not to be called
|
||||||
|
* if a decoding error occurs.
|
||||||
|
*
|
||||||
* Implementer's note: This method is defined by this interface in order
|
* Implementer's note: This method is defined by this interface in order
|
||||||
* to allow the output stream to efficiently copy the data from the input
|
* to allow the output stream to efficiently copy the data from the input
|
||||||
* stream into its internal buffer (if any). If this method was provide
|
* stream into its internal buffer (if any). If this method was provide
|
||||||
|
@ -82,11 +117,7 @@ interface imgIDecoder : nsISupports
|
||||||
* in order to call the output stream's other Write method.
|
* in order to call the output stream's other Write method.
|
||||||
* @param fromStream the stream from which the data is read
|
* @param fromStream the stream from which the data is read
|
||||||
* @param count the maximun number of bytes to write
|
* @param count the maximun number of bytes to write
|
||||||
* @return aWriteCount out parameter to hold the number of
|
|
||||||
* bytes written. if an error occurs, the writecount
|
|
||||||
* is undefined
|
|
||||||
*/
|
*/
|
||||||
unsigned long writeFrom(in nsIInputStream inStr,
|
void writeFrom(in nsIInputStream inStr, in unsigned long count);
|
||||||
in unsigned long count);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -52,16 +53,36 @@ interface imgIContainer;
|
||||||
* This interface is used both for observing imgIDecoder objects and for
|
* This interface is used both for observing imgIDecoder objects and for
|
||||||
* observing imgIRequest objects. In the former case, aRequest is
|
* observing imgIRequest objects. In the former case, aRequest is
|
||||||
* always null.
|
* always null.
|
||||||
* XXXldb The two functions should probably be split.
|
*
|
||||||
|
* We make the distinction here between "load" and "decode" notifications. Load
|
||||||
|
* notifications are fired as the image is loaded from the network or
|
||||||
|
* filesystem. Decode notifications are fired as the image is decoded. If an
|
||||||
|
* image is decoded on load and not visibly discarded, decode notifications are
|
||||||
|
* nested logically inside load notifications as one might expect. However, with
|
||||||
|
* decode-on-draw, the set of decode notifications can come completely _after_
|
||||||
|
* the load notifications, and can come multiple times if the image is
|
||||||
|
* discardable. Moreover, they can be interleaved in various ways. In general,
|
||||||
|
* any presumed ordering between load and decode notifications should not be
|
||||||
|
* relied upon.
|
||||||
|
*
|
||||||
|
* Decode notifications may or may not be synchronous, depending on the
|
||||||
|
* situation. If imgIDecoder::FLAG_SYNC_DECODE is passed to a function that
|
||||||
|
* triggers a decode, all notifications that can be generated from the currently
|
||||||
|
* loaded data fire before the call returns. If FLAG_SYNC_DECODE is not passed,
|
||||||
|
* all, some, or none of the notifications may fire before the call returns.
|
||||||
|
*
|
||||||
|
* This interface will be cleaned up in bug 505385.
|
||||||
*
|
*
|
||||||
* @author Stuart Parmenter <pavlov@netscape.com>
|
* @author Stuart Parmenter <pavlov@netscape.com>
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
* @see imagelib2
|
* @see imagelib2
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(1dfc9189-6421-4281-83b2-d9c1c9ba4d1b)]
|
[scriptable, uuid(9f6bfbee-9e04-43a0-b8f6-2159973efec8)]
|
||||||
interface imgIDecoderObserver : imgIContainerObserver
|
interface imgIDecoderObserver : imgIContainerObserver
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
* Load notification.
|
||||||
|
*
|
||||||
* called at the same time that nsIRequestObserver::onStartRequest would be
|
* called at the same time that nsIRequestObserver::onStartRequest would be
|
||||||
* (used only for observers of imgIRequest objects, which are nsIRequests,
|
* (used only for observers of imgIRequest objects, which are nsIRequests,
|
||||||
* not imgIDecoder objects)
|
* not imgIDecoder objects)
|
||||||
|
@ -72,42 +93,68 @@ interface imgIDecoderObserver : imgIContainerObserver
|
||||||
void onStartRequest(in imgIRequest aRequest);
|
void onStartRequest(in imgIRequest aRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called as soon as the image begins getting decoded
|
* Decode notification.
|
||||||
|
*
|
||||||
|
* Called as soon as the image begins getting decoded. This does not include
|
||||||
|
* "header-only" decodes used by decode-on-draw to parse the width/height
|
||||||
|
* out of the image. Thus, it is a decode notification only.
|
||||||
*/
|
*/
|
||||||
void onStartDecode(in imgIRequest aRequest);
|
void onStartDecode(in imgIRequest aRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called once the image has been inited and therefore has a width and height
|
* Load notification.
|
||||||
|
*
|
||||||
|
* Called once enough data has been loaded from the network that we were able
|
||||||
|
* to parse the width/height from the image. By the time this callback is been
|
||||||
|
* called, the size has been set on the container and STATUS_SIZE_AVAILABLE
|
||||||
|
* has been set on the associated imgRequest.
|
||||||
*/
|
*/
|
||||||
void onStartContainer(in imgIRequest aRequest, in imgIContainer aContainer);
|
void onStartContainer(in imgIRequest aRequest, in imgIContainer aContainer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called when each frame is created
|
* Decode notification.
|
||||||
|
*
|
||||||
|
* called when each frame is created.
|
||||||
*/
|
*/
|
||||||
void onStartFrame(in imgIRequest aRequest, in unsigned long aFrame);
|
void onStartFrame(in imgIRequest aRequest, in unsigned long aFrame);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called when some part of the frame has new data in it
|
* Decode notification.
|
||||||
|
*
|
||||||
|
* called when there is more to paint.
|
||||||
*/
|
*/
|
||||||
[noscript] void onDataAvailable(in imgIRequest aRequest, in boolean aCurrentFrame, [const] in nsIntRect aRect);
|
[noscript] void onDataAvailable(in imgIRequest aRequest, in boolean aCurrentFrame, [const] in nsIntRect aRect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called when a frame is finished decoding
|
* Decode notification.
|
||||||
|
*
|
||||||
|
* called when a frame is finished decoding.
|
||||||
*/
|
*/
|
||||||
void onStopFrame(in imgIRequest aRequest, in unsigned long aFrame);
|
void onStopFrame(in imgIRequest aRequest, in unsigned long aFrame);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* probably not needed. called right before onStopDecode
|
* Do not implement this. It is useless and going away.
|
||||||
*/
|
*/
|
||||||
void onStopContainer(in imgIRequest aRequest, in imgIContainer aContainer);
|
void onStopContainer(in imgIRequest aRequest, in imgIContainer aContainer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called when the decoder is dying off
|
* In theory a decode notification, but currently a load notification.
|
||||||
|
*
|
||||||
|
* Ideally this would be called when the decode is complete. Unfortunately,
|
||||||
|
* this is currently the only way to signal decoding errors to consumers,
|
||||||
|
* and the only decoding errors that consumers care about (indeed, the only
|
||||||
|
* ones that they're prepared to hear about) are failures to instantiate the
|
||||||
|
* decoder (<img src="foo.html"> for example). Thus, currently this is just
|
||||||
|
* a companion to onStopDecode to signal success or failure. This will be
|
||||||
|
* revisited in bug 505385. If you're thinking of doing something new with
|
||||||
|
* this, please talk to bholley first.
|
||||||
*/
|
*/
|
||||||
void onStopDecode(in imgIRequest aRequest, in nsresult status,
|
void onStopDecode(in imgIRequest aRequest, in nsresult status,
|
||||||
in wstring statusArg);
|
in wstring statusArg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Load notification.
|
||||||
|
*
|
||||||
* called at the same time that nsIRequestObserver::onStopRequest would be
|
* called at the same time that nsIRequestObserver::onStopRequest would be
|
||||||
* (used only for observers of imgIRequest objects, which are nsIRequests,
|
* (used only for observers of imgIRequest objects, which are nsIRequests,
|
||||||
* not imgIDecoder objects)
|
* not imgIDecoder objects)
|
||||||
|
@ -117,4 +164,11 @@ interface imgIDecoderObserver : imgIContainerObserver
|
||||||
*/
|
*/
|
||||||
void onStopRequest(in imgIRequest aRequest, in boolean aIsLastPart);
|
void onStopRequest(in imgIRequest aRequest, in boolean aIsLastPart);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the decoded image data is discarded. This means that the frames
|
||||||
|
* no longer exist in decoded form, and any attempt to access or draw the
|
||||||
|
* image will initiate a new series of progressive decode notifications.
|
||||||
|
*/
|
||||||
|
void onDiscard(in imgIRequest aRequest);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
||||||
*
|
|
||||||
* ***** BEGIN LICENSE BLOCK *****
|
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
||||||
*
|
|
||||||
* 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 the Initial Developer are Copyright (C) 2001
|
|
||||||
* the Initial Developer. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
||||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
||||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
||||||
* of those above. If you wish to allow use of your version of this file only
|
|
||||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
||||||
* use your version of this file under the terms of the MPL, indicate your
|
|
||||||
* decision by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
||||||
* the provisions above, a recipient may use your version of this file under
|
|
||||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
||||||
*
|
|
||||||
* ***** END LICENSE BLOCK ***** */
|
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
|
||||||
|
|
||||||
interface imgIContainer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* imgILoad interface
|
|
||||||
*
|
|
||||||
* @author Stuart Parmenter <pavlov@netscape.com>
|
|
||||||
* @version 0.1
|
|
||||||
* @see imagelib2
|
|
||||||
*/
|
|
||||||
[scriptable, uuid(e6273acc-1dd1-11b2-a08b-824ad1b1628d)]
|
|
||||||
interface imgILoad : nsISupports
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* the image container...
|
|
||||||
* @return the image object associated with the request.
|
|
||||||
* @attention NEED DOCS
|
|
||||||
*/
|
|
||||||
attribute imgIContainer image;
|
|
||||||
readonly attribute PRBool isMultiPartChannel;
|
|
||||||
};
|
|
|
@ -101,8 +101,7 @@ interface imgIRequest : nsIRequest
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* something
|
* Status flags of the STATUS_* variety.
|
||||||
* @attention NEED DOCS
|
|
||||||
*/
|
*/
|
||||||
readonly attribute unsigned long imageStatus;
|
readonly attribute unsigned long imageStatus;
|
||||||
|
|
||||||
|
@ -140,5 +139,41 @@ interface imgIRequest : nsIRequest
|
||||||
* you're the observer, you can't call cancel() from your destructor.
|
* you're the observer, you can't call cancel() from your destructor.
|
||||||
*/
|
*/
|
||||||
void cancelAndForgetObserver(in nsresult aStatus);
|
void cancelAndForgetObserver(in nsresult aStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a decode for the image.
|
||||||
|
*
|
||||||
|
* imgIContainer has a requestDecode() method, but callers may want to request
|
||||||
|
* a decode before the container has necessarily been instantiated. Calling
|
||||||
|
* requestDecode() on the imgIRequest simply forwards along the request if the
|
||||||
|
* container already exists, or calls it once it gets OnStartContainer if the
|
||||||
|
* container does not yet exist.
|
||||||
|
*/
|
||||||
|
void requestDecode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks an image. If the image does not exist yet, locks it once it becomes
|
||||||
|
* available. The lock persists for the lifetime of the imgIRequest (until
|
||||||
|
* unlockImage is called) even if the underlying image changes.
|
||||||
|
*
|
||||||
|
* If you don't call unlockImage() by the time this imgIRequest goes away, it
|
||||||
|
* will be called for you automatically.
|
||||||
|
*
|
||||||
|
* Only one lock at a time per imgIRequest is supported. That is to say, you
|
||||||
|
* can do foo->LockImage(); foo->UnlockImage(); foo->LockImage();
|
||||||
|
* foo->UnlockImage(); but not foo->LockImage(); foo->LockImage();
|
||||||
|
* foo->UnlockImage(); foo->UnlockImage();
|
||||||
|
*
|
||||||
|
* @see imgIContainer::lockImage for documentation of the underlying call.
|
||||||
|
*/
|
||||||
|
void lockImage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks an image.
|
||||||
|
*
|
||||||
|
* @see imgIContainer::unlockImage for documentation of the underlying call.
|
||||||
|
*/
|
||||||
|
void unlockImage();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,8 @@ interface imgITools : nsISupports
|
||||||
* @param aContainer
|
* @param aContainer
|
||||||
* An imgIContainer holding the decoded image. Specify |null| when
|
* An imgIContainer holding the decoded image. Specify |null| when
|
||||||
* calling to have one created, otherwise specify a container to
|
* calling to have one created, otherwise specify a container to
|
||||||
* be reused.
|
* be used. It is an error to pass an already-initialized container
|
||||||
|
* as aContainer.
|
||||||
*/
|
*/
|
||||||
void decodeImageData(in nsIInputStream aStream,
|
void decodeImageData(in nsIInputStream aStream,
|
||||||
in ACString aMimeType,
|
in ACString aMimeType,
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -24,6 +24,7 @@
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
* Chris Saari <saari@netscape.com>
|
* Chris Saari <saari@netscape.com>
|
||||||
* Federico Mena-Quintero <federico@novell.com>
|
* Federico Mena-Quintero <federico@novell.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -55,11 +56,14 @@
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
|
#include "imgIDecoder.h"
|
||||||
#include "nsIProperties.h"
|
#include "nsIProperties.h"
|
||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
#include "nsIStringStream.h"
|
||||||
#include "imgFrame.h"
|
#include "imgFrame.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
#define NS_IMGCONTAINER_CID \
|
#define NS_IMGCONTAINER_CID \
|
||||||
{ /* c76ff2c1-9bf6-418a-b143-3340c00112f7 */ \
|
{ /* c76ff2c1-9bf6-418a-b143-3340c00112f7 */ \
|
||||||
|
@ -131,9 +135,11 @@
|
||||||
* because the first two have public setters and the observer we only get
|
* because the first two have public setters and the observer we only get
|
||||||
* in Init().
|
* in Init().
|
||||||
*/
|
*/
|
||||||
|
class imgDecodeWorker;
|
||||||
class imgContainer : public imgIContainer,
|
class imgContainer : public imgIContainer,
|
||||||
public nsITimerCallback,
|
public nsITimerCallback,
|
||||||
public nsIProperties
|
public nsIProperties,
|
||||||
|
public nsSupportsWeakReference
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
@ -144,14 +150,19 @@ public:
|
||||||
imgContainer();
|
imgContainer();
|
||||||
virtual ~imgContainer();
|
virtual ~imgContainer();
|
||||||
|
|
||||||
|
static NS_METHOD WriteToContainer(nsIInputStream* in, void* closure,
|
||||||
|
const char* fromRawSegment,
|
||||||
|
PRUint32 toOffset, PRUint32 count,
|
||||||
|
PRUint32 *writeCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Anim
|
struct Anim
|
||||||
{
|
{
|
||||||
//! Area of the first frame that needs to be redrawn on subsequent loops.
|
//! Area of the first frame that needs to be redrawn on subsequent loops.
|
||||||
nsIntRect firstFrameRefreshArea;
|
nsIntRect firstFrameRefreshArea;
|
||||||
// Note this doesn't hold a proper value until frame 2 finished decoding.
|
// Note this doesn't hold a proper value until frame 2 finished decoding.
|
||||||
PRInt32 currentDecodingFrameIndex; // 0 to numFrames-1
|
PRUint32 currentDecodingFrameIndex; // 0 to numFrames-1
|
||||||
PRInt32 currentAnimationFrameIndex; // 0 to numFrames-1
|
PRUint32 currentAnimationFrameIndex; // 0 to numFrames-1
|
||||||
//! Track the last composited frame for Optimizations (See DoComposite code)
|
//! Track the last composited frame for Optimizations (See DoComposite code)
|
||||||
PRInt32 lastCompositedFrameIndex;
|
PRInt32 lastCompositedFrameIndex;
|
||||||
//! Whether we can assume there will be no more frames
|
//! Whether we can assume there will be no more frames
|
||||||
|
@ -197,11 +208,26 @@ private:
|
||||||
|
|
||||||
imgFrame* GetImgFrame(PRUint32 framenum);
|
imgFrame* GetImgFrame(PRUint32 framenum);
|
||||||
imgFrame* GetCurrentImgFrame();
|
imgFrame* GetCurrentImgFrame();
|
||||||
PRInt32 GetCurrentImgFrameIndex() const;
|
PRUint32 GetCurrentImgFrameIndex() const;
|
||||||
|
|
||||||
inline Anim* ensureAnimExists() {
|
inline Anim* ensureAnimExists()
|
||||||
if (!mAnim)
|
{
|
||||||
|
if (!mAnim) {
|
||||||
|
|
||||||
|
// Create the animation context
|
||||||
mAnim = new Anim();
|
mAnim = new Anim();
|
||||||
|
|
||||||
|
// We don't support discarding animated images (See bug 414259)
|
||||||
|
// Flag that we are no longer discardable (if we were before)
|
||||||
|
// and cancel any discard timer.
|
||||||
|
mDiscardable = PR_FALSE;
|
||||||
|
if (mDiscardTimer) {
|
||||||
|
nsresult rv = mDiscardTimer->Cancel();
|
||||||
|
if (!NS_SUCCEEDED(rv))
|
||||||
|
NS_WARNING("Discard Timer failed to cancel!");
|
||||||
|
mDiscardTimer = nsnull;
|
||||||
|
}
|
||||||
|
}
|
||||||
return mAnim;
|
return mAnim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,17 +282,19 @@ private:
|
||||||
private: // data
|
private: // data
|
||||||
|
|
||||||
nsIntSize mSize;
|
nsIntSize mSize;
|
||||||
|
PRBool mHasSize;
|
||||||
|
|
||||||
//! All the frames of the image
|
//! All the frames of the image
|
||||||
// *** IMPORTANT: if you use mFrames in a method, call RestoreDiscardedData() first to ensure
|
// IMPORTANT: if you use mFrames in a method, call EnsureImageIsDecoded() first
|
||||||
// that the frames actually exist (they may have been discarded to save memory).
|
// to ensure that the frames actually exist (they may have been discarded to save
|
||||||
|
// memory, or we may be decoding on draw).
|
||||||
nsTArray<imgFrame *> mFrames;
|
nsTArray<imgFrame *> mFrames;
|
||||||
int mNumFrames; /* stored separately from mFrames.Count() to support discarded images */
|
|
||||||
|
|
||||||
nsCOMPtr<nsIProperties> mProperties;
|
nsCOMPtr<nsIProperties> mProperties;
|
||||||
|
|
||||||
// *** IMPORTANT: if you use mAnim in a method, call RestoreDiscardedData() first to ensure
|
// IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
|
||||||
// that the frames actually exist (they may have been discarded to save memory).
|
// that the frames actually exist (they may have been discarded to save memory, or
|
||||||
|
// we maybe decoding on draw).
|
||||||
imgContainer::Anim* mAnim;
|
imgContainer::Anim* mAnim;
|
||||||
|
|
||||||
//! See imgIContainer for mode constants
|
//! See imgIContainer for mode constants
|
||||||
|
@ -275,21 +303,117 @@ private: // data
|
||||||
//! # loops remaining before animation stops (-1 no stop)
|
//! # loops remaining before animation stops (-1 no stop)
|
||||||
PRInt32 mLoopCount;
|
PRInt32 mLoopCount;
|
||||||
|
|
||||||
//! imgIContainerObserver
|
//! imgIDecoderObserver
|
||||||
nsWeakPtr mObserver;
|
nsWeakPtr mObserver;
|
||||||
|
|
||||||
PRBool mDiscardable;
|
// Decoding on draw?
|
||||||
PRBool mDiscarded;
|
PRBool mDecodeOnDraw;
|
||||||
nsCString mDiscardableMimeType;
|
|
||||||
|
|
||||||
nsTArray<char> mRestoreData;
|
// Multipart?
|
||||||
PRBool mRestoreDataDone;
|
PRBool mMultipart;
|
||||||
|
|
||||||
|
// Have we been initalized?
|
||||||
|
PRBool mInitialized;
|
||||||
|
|
||||||
|
// Discard members
|
||||||
|
PRBool mDiscardable;
|
||||||
|
PRUint32 mLockCount;
|
||||||
nsCOMPtr<nsITimer> mDiscardTimer;
|
nsCOMPtr<nsITimer> mDiscardTimer;
|
||||||
|
|
||||||
nsresult ResetDiscardTimer (void);
|
// Source data members
|
||||||
nsresult RestoreDiscardedData (void);
|
nsTArray<char> mSourceData;
|
||||||
nsresult ReloadImages (void);
|
PRBool mHasSourceData;
|
||||||
static void sDiscardTimerCallback (nsITimer *aTimer, void *aClosure);
|
nsCString mSourceDataMimeType;
|
||||||
|
|
||||||
|
// Do we have the frames in decoded form?
|
||||||
|
PRBool mDecoded;
|
||||||
|
|
||||||
|
friend class imgDecodeWorker;
|
||||||
|
|
||||||
|
// Decoder and friends
|
||||||
|
nsCOMPtr<imgIDecoder> mDecoder;
|
||||||
|
nsRefPtr<imgDecodeWorker> mWorker;
|
||||||
|
PRUint32 mBytesDecoded;
|
||||||
|
nsCOMPtr<nsIStringInputStream> mDecoderInput;
|
||||||
|
PRUint32 mDecoderFlags;
|
||||||
|
PRBool mWorkerPending;
|
||||||
|
PRBool mInDecoder;
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
PRBool mError;
|
||||||
|
|
||||||
|
// Discard code
|
||||||
|
nsresult ResetDiscardTimer();
|
||||||
|
static void sDiscardTimerCallback(nsITimer *aTimer, void *aClosure);
|
||||||
|
|
||||||
|
// Decoding
|
||||||
|
nsresult WantDecodedFrames();
|
||||||
|
nsresult SyncDecode();
|
||||||
|
nsresult InitDecoder(PRUint32 dFlags);
|
||||||
|
nsresult WriteToDecoder(const char *aBuffer, PRUint32 aCount);
|
||||||
|
nsresult DecodeSomeData(PRUint32 aMaxBytes);
|
||||||
|
PRBool IsDecodeFinished();
|
||||||
|
nsresult EnableDiscarding();
|
||||||
|
|
||||||
|
// Decoder shutdown
|
||||||
|
enum eShutdownIntent {
|
||||||
|
eShutdownIntent_Done = 0,
|
||||||
|
eShutdownIntent_Interrupted = 1,
|
||||||
|
eShutdownIntent_Error = 2,
|
||||||
|
eShutdownIntent_AllCount = 3
|
||||||
|
};
|
||||||
|
nsresult ShutdownDecoder(eShutdownIntent aIntent);
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
void DoError();
|
||||||
|
PRBool CanDiscard();
|
||||||
|
PRBool StoringSourceData();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Decoding Helper Class
|
||||||
|
//
|
||||||
|
// We use this class to mimic the interactivity benefits of threading
|
||||||
|
// in a single-threaded event loop. We want to progressively decode
|
||||||
|
// and keep a responsive UI while we're at it, so we have a runnable
|
||||||
|
// class that does a bit of decoding, and then "yields" by dispatching
|
||||||
|
// itself to the end of the event queue.
|
||||||
|
class imgDecodeWorker : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
imgDecodeWorker(imgIContainer* aContainer) {
|
||||||
|
mContainer = do_GetWeakReference(aContainer);
|
||||||
|
}
|
||||||
|
NS_IMETHOD Run();
|
||||||
|
NS_METHOD Dispatch();
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsWeakPtr mContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Asynchronous Decode Requestor
|
||||||
|
//
|
||||||
|
// We use this class when someone calls requestDecode() from within a decode
|
||||||
|
// notification. Since requestDecode() involves modifying the decoder's state
|
||||||
|
// (for example, possibly shutting down a header-only decode and starting a
|
||||||
|
// full decode), we don't want to do this from inside a decoder.
|
||||||
|
class imgDecodeRequestor : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
imgDecodeRequestor(imgIContainer *aContainer) {
|
||||||
|
mContainer = do_GetWeakReference(aContainer);
|
||||||
|
}
|
||||||
|
NS_IMETHOD Run() {
|
||||||
|
nsCOMPtr<imgIContainer> con = do_QueryReferent(mContainer);
|
||||||
|
if (con)
|
||||||
|
con->RequestDecode();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsWeakPtr mContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __imgContainer_h__ */
|
#endif /* __imgContainer_h__ */
|
||||||
|
|
|
@ -102,7 +102,7 @@ static void PrintImageDecoders()
|
||||||
nsCAutoString xcs;
|
nsCAutoString xcs;
|
||||||
ss->GetData(xcs);
|
ss->GetData(xcs);
|
||||||
|
|
||||||
NS_NAMED_LITERAL_CSTRING(decoderContract, "@mozilla.org/image/decoder;2?type=");
|
NS_NAMED_LITERAL_CSTRING(decoderContract, "@mozilla.org/image/decoder;3?type=");
|
||||||
|
|
||||||
if (StringBeginsWith(xcs, decoderContract)) {
|
if (StringBeginsWith(xcs, decoderContract)) {
|
||||||
printf("Have decoder for mime type: %s\n", xcs.get()+decoderContract.Length());
|
printf("Have decoder for mime type: %s\n", xcs.get()+decoderContract.Length());
|
||||||
|
@ -372,21 +372,6 @@ imgCacheEntry::~imgCacheEntry()
|
||||||
LOG_FUNC(gImgLog, "imgCacheEntry::~imgCacheEntry()");
|
LOG_FUNC(gImgLog, "imgCacheEntry::~imgCacheEntry()");
|
||||||
}
|
}
|
||||||
|
|
||||||
void imgCacheEntry::TouchWithSize(PRInt32 diff)
|
|
||||||
{
|
|
||||||
LOG_SCOPE(gImgLog, "imgCacheEntry::TouchWithSize");
|
|
||||||
|
|
||||||
mTouchedTime = SecondsFromPRTime(PR_Now());
|
|
||||||
|
|
||||||
// Don't update the cache if we've been removed from it or it doesn't care
|
|
||||||
// about our size or usage.
|
|
||||||
if (!Evicted() && HasNoProxies()) {
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
mRequest->GetKeyURI(getter_AddRefs(uri));
|
|
||||||
imgLoader::CacheEntriesChanged(uri, diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void imgCacheEntry::Touch(PRBool updateTime /* = PR_TRUE */)
|
void imgCacheEntry::Touch(PRBool updateTime /* = PR_TRUE */)
|
||||||
{
|
{
|
||||||
LOG_SCOPE(gImgLog, "imgCacheEntry::Touch");
|
LOG_SCOPE(gImgLog, "imgCacheEntry::Touch");
|
||||||
|
@ -394,12 +379,17 @@ void imgCacheEntry::Touch(PRBool updateTime /* = PR_TRUE */)
|
||||||
if (updateTime)
|
if (updateTime)
|
||||||
mTouchedTime = SecondsFromPRTime(PR_Now());
|
mTouchedTime = SecondsFromPRTime(PR_Now());
|
||||||
|
|
||||||
|
UpdateCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
void imgCacheEntry::UpdateCache(PRInt32 diff /* = 0 */)
|
||||||
|
{
|
||||||
// Don't update the cache if we've been removed from it or it doesn't care
|
// Don't update the cache if we've been removed from it or it doesn't care
|
||||||
// about our size or usage.
|
// about our size or usage.
|
||||||
if (!Evicted() && HasNoProxies()) {
|
if (!Evicted() && HasNoProxies()) {
|
||||||
nsCOMPtr<nsIURI> uri;
|
nsCOMPtr<nsIURI> uri;
|
||||||
mRequest->GetKeyURI(getter_AddRefs(uri));
|
mRequest->GetKeyURI(getter_AddRefs(uri));
|
||||||
imgLoader::CacheEntriesChanged(uri);
|
imgLoader::CacheEntriesChanged(uri, diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1641,7 +1631,7 @@ NS_IMETHODIMP imgLoader::SupportImageWithMimeType(const char* aMimeType, PRBool
|
||||||
return rv;
|
return rv;
|
||||||
nsCAutoString mimeType(aMimeType);
|
nsCAutoString mimeType(aMimeType);
|
||||||
ToLowerCase(mimeType);
|
ToLowerCase(mimeType);
|
||||||
nsCAutoString decoderId(NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + mimeType);
|
nsCAutoString decoderId(NS_LITERAL_CSTRING("@mozilla.org/image/decoder;3?type=") + mimeType);
|
||||||
return reg->IsContractIDRegistered(decoderId.get(), _retval);
|
return reg->IsContractIDRegistered(decoderId.get(), _retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ public:
|
||||||
{
|
{
|
||||||
PRInt32 oldsize = mDataSize;
|
PRInt32 oldsize = mDataSize;
|
||||||
mDataSize = aDataSize;
|
mDataSize = aDataSize;
|
||||||
TouchWithSize(mDataSize - oldsize);
|
UpdateCache(mDataSize - oldsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt32 GetTouchedTime() const
|
PRInt32 GetTouchedTime() const
|
||||||
|
@ -156,7 +156,7 @@ private: // methods
|
||||||
friend class imgLoader;
|
friend class imgLoader;
|
||||||
friend class imgCacheQueue;
|
friend class imgCacheQueue;
|
||||||
void Touch(PRBool updateTime = PR_TRUE);
|
void Touch(PRBool updateTime = PR_TRUE);
|
||||||
void TouchWithSize(PRInt32 diff);
|
void UpdateCache(PRInt32 diff = 0);
|
||||||
void SetEvicted(PRBool evict)
|
void SetEvicted(PRBool evict)
|
||||||
{
|
{
|
||||||
mEvicted = evict;
|
mEvicted = evict;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <stuart@mozilla.com>
|
* Stuart Parmenter <stuart@mozilla.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
|
|
||||||
#include "imgLoader.h"
|
#include "imgLoader.h"
|
||||||
#include "imgRequestProxy.h"
|
#include "imgRequestProxy.h"
|
||||||
|
#include "imgContainer.h"
|
||||||
|
|
||||||
#include "imgILoader.h"
|
#include "imgILoader.h"
|
||||||
#include "ImageErrors.h"
|
#include "ImageErrors.h"
|
||||||
|
@ -68,11 +70,14 @@
|
||||||
#include "nsXPIDLString.h"
|
#include "nsXPIDLString.h"
|
||||||
#include "plstr.h" // PL_strcasestr(...)
|
#include "plstr.h" // PL_strcasestr(...)
|
||||||
|
|
||||||
|
static PRBool gDecodeOnDraw = PR_TRUE;
|
||||||
|
static PRBool gDiscardable = PR_TRUE;
|
||||||
|
|
||||||
#if defined(PR_LOGGING)
|
#if defined(PR_LOGGING)
|
||||||
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
|
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS8(imgRequest, imgILoad,
|
NS_IMPL_ISUPPORTS7(imgRequest,
|
||||||
imgIDecoderObserver, imgIContainerObserver,
|
imgIDecoderObserver, imgIContainerObserver,
|
||||||
nsIStreamListener, nsIRequestObserver,
|
nsIStreamListener, nsIRequestObserver,
|
||||||
nsISupportsWeakReference,
|
nsISupportsWeakReference,
|
||||||
|
@ -82,7 +87,7 @@ NS_IMPL_ISUPPORTS8(imgRequest, imgILoad,
|
||||||
imgRequest::imgRequest() :
|
imgRequest::imgRequest() :
|
||||||
mImageStatus(imgIRequest::STATUS_NONE), mState(0), mCacheId(0),
|
mImageStatus(imgIRequest::STATUS_NONE), mState(0), mCacheId(0),
|
||||||
mValidator(nsnull), mImageSniffers("image-sniffing-services"),
|
mValidator(nsnull), mImageSniffers("image-sniffing-services"),
|
||||||
mIsMultiPartChannel(PR_FALSE), mLoading(PR_FALSE), mProcessing(PR_FALSE),
|
mIsMultiPartChannel(PR_FALSE), mLoading(PR_FALSE),
|
||||||
mHadLastPart(PR_FALSE), mGotData(PR_FALSE), mIsInCache(PR_FALSE)
|
mHadLastPart(PR_FALSE), mGotData(PR_FALSE), mIsInCache(PR_FALSE)
|
||||||
{
|
{
|
||||||
/* member initializers and constructor code */
|
/* member initializers and constructor code */
|
||||||
|
@ -186,14 +191,14 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBoo
|
||||||
|
|
||||||
if (aNotify) {
|
if (aNotify) {
|
||||||
// make sure that observer gets an OnStopDecode message sent to it
|
// make sure that observer gets an OnStopDecode message sent to it
|
||||||
if (!(mState & onStopDecode)) {
|
if (!(mState & stateRequestStopped)) {
|
||||||
proxy->OnStopDecode(aStatus, nsnull);
|
proxy->OnStopDecode(aStatus, nsnull);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that observer gets an OnStopRequest message sent to it
|
// make sure that observer gets an OnStopRequest message sent to it
|
||||||
if (!(mState & onStopRequest)) {
|
if (!(mState & stateRequestStopped)) {
|
||||||
proxy->OnStopRequest(nsnull, nsnull, NS_BINDING_ABORTED, PR_TRUE);
|
proxy->OnStopRequest(nsnull, nsnull, NS_BINDING_ABORTED, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,17 +255,17 @@ nsresult imgRequest::NotifyProxyListener(imgRequestProxy *proxy)
|
||||||
nsCOMPtr<imgIRequest> kungFuDeathGrip(proxy);
|
nsCOMPtr<imgIRequest> kungFuDeathGrip(proxy);
|
||||||
|
|
||||||
// OnStartRequest
|
// OnStartRequest
|
||||||
if (mState & onStartRequest)
|
if (mState & stateRequestStarted)
|
||||||
proxy->OnStartRequest(nsnull, nsnull);
|
proxy->OnStartRequest(nsnull, nsnull);
|
||||||
|
|
||||||
// OnStartDecode
|
|
||||||
if (mState & onStartDecode)
|
|
||||||
proxy->OnStartDecode();
|
|
||||||
|
|
||||||
// OnStartContainer
|
// OnStartContainer
|
||||||
if (mState & onStartContainer)
|
if (mState & stateHasSize)
|
||||||
proxy->OnStartContainer(mImage);
|
proxy->OnStartContainer(mImage);
|
||||||
|
|
||||||
|
// OnStartDecode
|
||||||
|
if (mState & stateDecodeStarted)
|
||||||
|
proxy->OnStartDecode();
|
||||||
|
|
||||||
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
|
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
|
||||||
PRUint32 nframes = 0;
|
PRUint32 nframes = 0;
|
||||||
if (mImage)
|
if (mImage)
|
||||||
|
@ -271,29 +276,16 @@ nsresult imgRequest::NotifyProxyListener(imgRequestProxy *proxy)
|
||||||
mImage->GetCurrentFrameIndex(&frame);
|
mImage->GetCurrentFrameIndex(&frame);
|
||||||
proxy->OnStartFrame(frame);
|
proxy->OnStartFrame(frame);
|
||||||
|
|
||||||
if (!(mState & onStopContainer)) {
|
|
||||||
// OnDataAvailable
|
// OnDataAvailable
|
||||||
|
// XXX - Should only send partial rects here, but that needs to
|
||||||
|
// wait until we fix up the observer interface
|
||||||
nsIntRect r;
|
nsIntRect r;
|
||||||
mImage->GetCurrentFrameRect(r); // XXX we should only send the currently decoded rectangle here.
|
mImage->GetCurrentFrameRect(r);
|
||||||
proxy->OnDataAvailable(frame, &r);
|
|
||||||
} else {
|
|
||||||
// OnDataAvailable
|
|
||||||
nsIntRect r;
|
|
||||||
mImage->GetCurrentFrameRect(r); // We're done loading this image, send the the whole rect
|
|
||||||
proxy->OnDataAvailable(frame, &r);
|
proxy->OnDataAvailable(frame, &r);
|
||||||
|
|
||||||
// OnStopFrame
|
if (mState & stateRequestStopped)
|
||||||
proxy->OnStopFrame(frame);
|
proxy->OnStopFrame(frame);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// OnStopContainer
|
|
||||||
if (mState & onStopContainer)
|
|
||||||
proxy->OnStopContainer(mImage);
|
|
||||||
|
|
||||||
// OnStopDecode
|
|
||||||
if (mState & onStopDecode)
|
|
||||||
proxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull);
|
|
||||||
|
|
||||||
if (mImage && !HaveProxyWithObserver(proxy) && proxy->HasObserver()) {
|
if (mImage && !HaveProxyWithObserver(proxy) && proxy->HasObserver()) {
|
||||||
LOG_MSG(gImgLog, "imgRequest::NotifyProxyListener", "resetting animation");
|
LOG_MSG(gImgLog, "imgRequest::NotifyProxyListener", "resetting animation");
|
||||||
|
@ -301,7 +293,9 @@ nsresult imgRequest::NotifyProxyListener(imgRequestProxy *proxy)
|
||||||
mImage->ResetAnimation();
|
mImage->ResetAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState & onStopRequest) {
|
if (mState & stateRequestStopped) {
|
||||||
|
proxy->OnStopContainer(mImage);
|
||||||
|
proxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull);
|
||||||
proxy->OnStopRequest(nsnull, nsnull,
|
proxy->OnStopRequest(nsnull, nsnull,
|
||||||
GetResultFromImageStatus(mImageStatus),
|
GetResultFromImageStatus(mImageStatus),
|
||||||
mHadLastPart);
|
mHadLastPart);
|
||||||
|
@ -337,9 +331,7 @@ void imgRequest::Cancel(nsresult aStatus)
|
||||||
if (!(mImageStatus & imgIRequest::STATUS_LOAD_PARTIAL))
|
if (!(mImageStatus & imgIRequest::STATUS_LOAD_PARTIAL))
|
||||||
mImageStatus |= imgIRequest::STATUS_ERROR;
|
mImageStatus |= imgIRequest::STATUS_ERROR;
|
||||||
|
|
||||||
if (aStatus != NS_IMAGELIB_ERROR_NO_DECODER) {
|
|
||||||
RemoveFromCache();
|
RemoveFromCache();
|
||||||
}
|
|
||||||
|
|
||||||
if (mRequest && mLoading)
|
if (mRequest && mLoading)
|
||||||
mRequest->Cancel(aStatus);
|
mRequest->Cancel(aStatus);
|
||||||
|
@ -473,18 +465,25 @@ void imgRequest::SetIsInCache(PRBool incache)
|
||||||
mIsInCache = incache;
|
mIsInCache = incache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** imgILoad methods **/
|
void imgRequest::UpdateCacheEntrySize()
|
||||||
|
|
||||||
NS_IMETHODIMP imgRequest::SetImage(imgIContainer *aImage)
|
|
||||||
{
|
{
|
||||||
LOG_FUNC(gImgLog, "imgRequest::SetImage");
|
if (mCacheEntry) {
|
||||||
|
PRUint32 imageSize = 0;
|
||||||
|
if (mImage)
|
||||||
|
mImage->GetDataSize(&imageSize);
|
||||||
|
mCacheEntry->SetDataSize(imageSize);
|
||||||
|
|
||||||
mImage = aImage;
|
#ifdef DEBUG_joe
|
||||||
|
nsCAutoString url;
|
||||||
|
mURI->GetSpec(url);
|
||||||
|
printf("CACHEPUT: %d %s %d\n", time(NULL), url.get(), imageSize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP imgRequest::GetImage(imgIContainer **aImage)
|
nsresult
|
||||||
|
imgRequest::GetImage(imgIContainer **aImage)
|
||||||
{
|
{
|
||||||
LOG_FUNC(gImgLog, "imgRequest::GetImage");
|
LOG_FUNC(gImgLog, "imgRequest::GetImage");
|
||||||
|
|
||||||
|
@ -493,15 +492,6 @@ NS_IMETHODIMP imgRequest::GetImage(imgIContainer **aImage)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP imgRequest::GetIsMultiPartChannel(PRBool *aIsMultiPartChannel)
|
|
||||||
{
|
|
||||||
LOG_FUNC(gImgLog, "imgRequest::GetIsMultiPartChannel");
|
|
||||||
|
|
||||||
*aIsMultiPartChannel = mIsMultiPartChannel;
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** imgIContainerObserver methods **/
|
/** imgIContainerObserver methods **/
|
||||||
|
|
||||||
/* [noscript] void frameChanged (in imgIContainer container, in nsIntRect dirtyRect); */
|
/* [noscript] void frameChanged (in imgIContainer container, in nsIntRect dirtyRect); */
|
||||||
|
@ -525,7 +515,7 @@ NS_IMETHODIMP imgRequest::OnStartDecode(imgIRequest *request)
|
||||||
{
|
{
|
||||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartDecode");
|
LOG_SCOPE(gImgLog, "imgRequest::OnStartDecode");
|
||||||
|
|
||||||
mState |= onStartDecode;
|
mState |= stateDecodeStarted;
|
||||||
|
|
||||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
|
@ -557,14 +547,19 @@ NS_IMETHODIMP imgRequest::OnStartContainer(imgIRequest *request, imgIContainer *
|
||||||
NS_ASSERTION(image, "imgRequest::OnStartContainer called with a null image!");
|
NS_ASSERTION(image, "imgRequest::OnStartContainer called with a null image!");
|
||||||
if (!image) return NS_ERROR_UNEXPECTED;
|
if (!image) return NS_ERROR_UNEXPECTED;
|
||||||
|
|
||||||
mState |= onStartContainer;
|
// We only want to send onStartContainer once
|
||||||
|
PRBool alreadySent = (mState & stateHasSize) != 0;
|
||||||
|
|
||||||
|
mState |= stateHasSize;
|
||||||
|
|
||||||
mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE;
|
mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE;
|
||||||
|
|
||||||
|
if (!alreadySent) {
|
||||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
iter.GetNext()->OnStartContainer(image);
|
iter.GetNext()->OnStartContainer(image);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -606,23 +601,6 @@ NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request,
|
||||||
|
|
||||||
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE;
|
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE;
|
||||||
|
|
||||||
if (mCacheEntry) {
|
|
||||||
PRUint32 cacheSize = mCacheEntry->GetDataSize();
|
|
||||||
|
|
||||||
PRUint32 imageSize = 0;
|
|
||||||
if (mImage)
|
|
||||||
mImage->GetFrameImageDataLength(frame, &imageSize);
|
|
||||||
|
|
||||||
mCacheEntry->SetDataSize(cacheSize + imageSize);
|
|
||||||
|
|
||||||
#ifdef DEBUG_joe
|
|
||||||
nsCAutoString url;
|
|
||||||
mURI->GetSpec(url);
|
|
||||||
|
|
||||||
printf("CACHEPUT: %d %s %d\n", time(NULL), url.get(), cacheSize + imageSize);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
iter.GetNext()->OnStopFrame(frame);
|
iter.GetNext()->OnStopFrame(frame);
|
||||||
|
@ -637,8 +615,6 @@ NS_IMETHODIMP imgRequest::OnStopContainer(imgIRequest *request,
|
||||||
{
|
{
|
||||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopContainer");
|
LOG_SCOPE(gImgLog, "imgRequest::OnStopContainer");
|
||||||
|
|
||||||
mState |= onStopContainer;
|
|
||||||
|
|
||||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
iter.GetNext()->OnStopContainer(image);
|
iter.GetNext()->OnStopContainer(image);
|
||||||
|
@ -654,18 +630,21 @@ NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest,
|
||||||
{
|
{
|
||||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopDecode");
|
LOG_SCOPE(gImgLog, "imgRequest::OnStopDecode");
|
||||||
|
|
||||||
NS_ASSERTION(!(mState & onStopDecode), "OnStopDecode called multiple times.");
|
// We finished the decode, and thus have the decoded frames. Update the cache
|
||||||
|
// entry size to take this into account.
|
||||||
|
UpdateCacheEntrySize();
|
||||||
|
|
||||||
mState |= onStopDecode;
|
// ImgContainer and everything below it is completely correct and
|
||||||
|
// bulletproof about its handling of decoder notifications.
|
||||||
if (NS_FAILED(aStatus) && !(mImageStatus & imgIRequest::STATUS_LOAD_PARTIAL)) {
|
// Unfortunately, here and above we have to make some gross and
|
||||||
mImageStatus |= imgIRequest::STATUS_ERROR;
|
// inappropriate use of things to get things to work without
|
||||||
}
|
// completely overhauling the decoder observer interface (this will,
|
||||||
|
// thankfully, happen in bug 505385). From imgRequest and above (for
|
||||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
// the time being), OnStopDecode is just a companion to OnStopRequest
|
||||||
while (iter.HasMore()) {
|
// that signals success or failure of the _load_ (not the _decode_).
|
||||||
iter.GetNext()->OnStopDecode(GetResultFromImageStatus(mImageStatus), aStatusArg);
|
// As such, we ignore OnStopDecode notifications from the decoder and
|
||||||
}
|
// container and generate our own every time we send OnStopRequest.
|
||||||
|
// For more information, see bug 435296.
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -677,6 +656,29 @@ NS_IMETHODIMP imgRequest::OnStopRequest(imgIRequest *aRequest,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* void onDiscard (in imgIRequest request); */
|
||||||
|
NS_IMETHODIMP imgRequest::OnDiscard(imgIRequest *aRequest)
|
||||||
|
{
|
||||||
|
// Clear the state bits we no longer deserve.
|
||||||
|
PRUint32 stateBitsToClear = stateDecodeStarted;
|
||||||
|
mState &= ~stateBitsToClear;
|
||||||
|
|
||||||
|
// Clear the status bits we no longer deserve.
|
||||||
|
PRUint32 statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE;
|
||||||
|
mImageStatus &= ~statusBitsToClear;
|
||||||
|
|
||||||
|
// Update the cache entry size, since we just got rid of frame data
|
||||||
|
UpdateCacheEntrySize();
|
||||||
|
|
||||||
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||||
|
while (iter.HasMore()) {
|
||||||
|
iter.GetNext()->OnDiscard();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** nsIRequestObserver methods **/
|
/** nsIRequestObserver methods **/
|
||||||
|
|
||||||
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
|
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
|
||||||
|
@ -686,12 +688,30 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
|
||||||
|
|
||||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartRequest");
|
LOG_SCOPE(gImgLog, "imgRequest::OnStartRequest");
|
||||||
|
|
||||||
NS_ASSERTION(!mDecoder, "imgRequest::OnStartRequest -- we already have a decoder");
|
// Figure out if we're multipart
|
||||||
|
|
||||||
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
|
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
|
||||||
if (mpchan)
|
if (mpchan)
|
||||||
mIsMultiPartChannel = PR_TRUE;
|
mIsMultiPartChannel = PR_TRUE;
|
||||||
|
|
||||||
|
// If we're not multipart, we shouldn't have an image yet
|
||||||
|
NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
|
||||||
|
"Already have an image for non-multipart request");
|
||||||
|
|
||||||
|
// If we're multipart and have an image, fix things up for another round
|
||||||
|
if (mIsMultiPartChannel && mImage) {
|
||||||
|
|
||||||
|
// Inform the container that we have new source data
|
||||||
|
mImage->NewSourceData();
|
||||||
|
|
||||||
|
// Clear any status and state bits indicating load/decode
|
||||||
|
mImageStatus &= ~imgIRequest::STATUS_LOAD_PARTIAL;
|
||||||
|
mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
|
||||||
|
mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
|
||||||
|
mState &= ~stateRequestStarted;
|
||||||
|
mState &= ~stateDecodeStarted;
|
||||||
|
mState &= ~stateRequestStopped;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If mRequest is null here, then we need to set it so that we'll be able to
|
* If mRequest is null here, then we need to set it so that we'll be able to
|
||||||
* cancel it if our Cancel() method is called. Note that this can only
|
* cancel it if our Cancel() method is called. Note that this can only
|
||||||
|
@ -707,10 +727,8 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
|
||||||
mRequest = chan;
|
mRequest = chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set our state variables to their initial values, but advance mState
|
// The request has started
|
||||||
to onStartRequest. */
|
mState |= stateRequestStarted;
|
||||||
mImageStatus = imgIRequest::STATUS_NONE;
|
|
||||||
mState = onStartRequest;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
|
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
|
||||||
if (channel)
|
if (channel)
|
||||||
|
@ -802,14 +820,11 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
|
||||||
{
|
{
|
||||||
LOG_FUNC(gImgLog, "imgRequest::OnStopRequest");
|
LOG_FUNC(gImgLog, "imgRequest::OnStopRequest");
|
||||||
|
|
||||||
mState |= onStopRequest;
|
mState |= stateRequestStopped;
|
||||||
|
|
||||||
/* set our loading flag to false */
|
/* set our loading flag to false */
|
||||||
mLoading = PR_FALSE;
|
mLoading = PR_FALSE;
|
||||||
|
|
||||||
/* set our processing flag to false */
|
|
||||||
mProcessing = PR_FALSE;
|
|
||||||
|
|
||||||
mHadLastPart = PR_TRUE;
|
mHadLastPart = PR_TRUE;
|
||||||
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
|
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
|
||||||
if (mpchan) {
|
if (mpchan) {
|
||||||
|
@ -834,39 +849,55 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
|
||||||
mChannel = nsnull;
|
mChannel = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If mImage is still null, we didn't properly load the image.
|
// Tell the image that it has all of the source data. Note that this can
|
||||||
if (NS_FAILED(status) || !mImage) {
|
// trigger a failure, since the image might be waiting for more non-optional
|
||||||
this->Cancel(status); // sets status, stops animations, removes from cache
|
// data and this is the point where we break the news that it's not coming.
|
||||||
} else {
|
if (mImage) {
|
||||||
|
|
||||||
|
// Notify the image
|
||||||
|
nsresult rv = mImage->SourceDataComplete();
|
||||||
|
|
||||||
|
// If we got an error in the SourceDataComplete() call, we don't want to
|
||||||
|
// proceed as if nothing bad happened. However, we also want to give
|
||||||
|
// precedence to failure status codes from necko, since presumably
|
||||||
|
// they're more meaningful.
|
||||||
|
if (NS_FAILED(rv) && NS_SUCCEEDED(status))
|
||||||
|
status = rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the request went through, say we loaded the image, and update the
|
||||||
|
// cache entry size. Otherwise, cancel the request, which adds an error
|
||||||
|
// flag to mImageStatus.
|
||||||
|
if (NS_SUCCEEDED(status)) {
|
||||||
|
|
||||||
|
// Flag that we loaded the image
|
||||||
mImageStatus |= imgIRequest::STATUS_LOAD_COMPLETE;
|
mImageStatus |= imgIRequest::STATUS_LOAD_COMPLETE;
|
||||||
}
|
|
||||||
|
|
||||||
if (mDecoder) {
|
// We update the cache entry size here because this is where we finish
|
||||||
mDecoder->Flush();
|
// loading compressed source data, which is part of our size calculus.
|
||||||
mDecoder->Close();
|
UpdateCacheEntrySize();
|
||||||
mDecoder = nsnull; // release the decoder so that it can rest peacefully ;)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there was an error loading the image, (mState & onStopDecode) won't be true.
|
|
||||||
// Send an onStopDecode message
|
|
||||||
if (!(mState & onStopDecode)) {
|
|
||||||
this->OnStopDecode(nsnull, status, nsnull);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
this->Cancel(status); // sets status, stops animations, removes from cache
|
||||||
|
|
||||||
/* notify the kids */
|
/* notify the kids */
|
||||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator sdIter(mObservers);
|
||||||
while (iter.HasMore()) {
|
while (sdIter.HasMore()) {
|
||||||
iter.GetNext()->OnStopRequest(aRequest, ctxt, status, mHadLastPart);
|
sdIter.GetNext()->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTObserverArray<imgRequestProxy*>::ForwardIterator srIter(mObservers);
|
||||||
|
while (srIter.HasMore()) {
|
||||||
|
srIter.GetNext()->OnStopRequest(aRequest, ctxt, status, mHadLastPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prototype for this defined below */
|
/* prototype for these defined below */
|
||||||
static NS_METHOD sniff_mimetype_callback(nsIInputStream* in, void* closure, const char* fromRawSegment,
|
static NS_METHOD sniff_mimetype_callback(nsIInputStream* in, void* closure, const char* fromRawSegment,
|
||||||
PRUint32 toOffset, PRUint32 count, PRUint32 *writeCount);
|
PRUint32 toOffset, PRUint32 count, PRUint32 *writeCount);
|
||||||
|
|
||||||
|
|
||||||
/** nsIStreamListener methods **/
|
/** nsIStreamListener methods **/
|
||||||
|
|
||||||
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
|
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
|
||||||
|
@ -877,13 +908,11 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
|
||||||
NS_ASSERTION(aRequest, "imgRequest::OnDataAvailable -- no request!");
|
NS_ASSERTION(aRequest, "imgRequest::OnDataAvailable -- no request!");
|
||||||
|
|
||||||
mGotData = PR_TRUE;
|
mGotData = PR_TRUE;
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
if (!mProcessing) {
|
if (!mImage) {
|
||||||
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |First time through... finding mimetype|");
|
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |First time through... finding mimetype|");
|
||||||
|
|
||||||
/* set our processing flag to true if this is the first OnDataAvailable() */
|
|
||||||
mProcessing = PR_TRUE;
|
|
||||||
|
|
||||||
/* look at the first few bytes and see if we can tell what the data is from that
|
/* look at the first few bytes and see if we can tell what the data is from that
|
||||||
* since servers tend to lie. :(
|
* since servers tend to lie. :(
|
||||||
*/
|
*/
|
||||||
|
@ -899,7 +928,7 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
|
||||||
|
|
||||||
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
|
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
|
||||||
|
|
||||||
nsresult rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
if (chan) {
|
if (chan) {
|
||||||
rv = chan->GetContentType(mContentType);
|
rv = chan->GetContentType(mContentType);
|
||||||
}
|
}
|
||||||
|
@ -945,51 +974,79 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
|
||||||
|
|
||||||
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnDataAvailable", "content type", mContentType.get());
|
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnDataAvailable", "content type", mContentType.get());
|
||||||
|
|
||||||
nsCAutoString conid(NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + mContentType);
|
//
|
||||||
|
// Figure out if our container initialization flags
|
||||||
|
//
|
||||||
|
|
||||||
mDecoder = do_CreateInstance(conid.get());
|
// We default to the static globals
|
||||||
|
PRBool isDiscardable = gDiscardable;
|
||||||
|
PRBool doDecodeOnDraw = gDecodeOnDraw;
|
||||||
|
|
||||||
if (!mDecoder) {
|
// We want UI to be as snappy as possible and not to flicker. Disable discarding
|
||||||
PR_LOG(gImgLog, PR_LOG_WARNING,
|
// and decode-on-draw for chrome URLS
|
||||||
("[this=%p] imgRequest::OnDataAvailable -- Decoder not available\n", this));
|
PRBool isChrome = PR_FALSE;
|
||||||
|
rv = mURI->SchemeIs("chrome", &isChrome);
|
||||||
|
if (NS_SUCCEEDED(rv) && isChrome)
|
||||||
|
isDiscardable = doDecodeOnDraw = PR_FALSE;
|
||||||
|
|
||||||
// no image decoder for this mimetype :(
|
// We don't want resources like the "loading" icon to be discardable or
|
||||||
this->Cancel(NS_IMAGELIB_ERROR_NO_DECODER);
|
// decode-on-draw either.
|
||||||
|
PRBool isResource = PR_FALSE;
|
||||||
|
rv = mURI->SchemeIs("resource", &isResource);
|
||||||
|
if (NS_SUCCEEDED(rv) && isResource)
|
||||||
|
isDiscardable = doDecodeOnDraw = PR_FALSE;
|
||||||
|
|
||||||
return NS_IMAGELIB_ERROR_NO_DECODER;
|
// For multipart/x-mixed-replace, we basically want a direct channel to the
|
||||||
|
// decoder. Disable both for this case as well.
|
||||||
|
if (mIsMultiPartChannel)
|
||||||
|
isDiscardable = doDecodeOnDraw = PR_FALSE;
|
||||||
|
|
||||||
|
// We have all the information we need
|
||||||
|
PRUint32 containerFlags = imgIContainer::INIT_FLAG_NONE;
|
||||||
|
if (isDiscardable)
|
||||||
|
containerFlags |= imgIContainer::INIT_FLAG_DISCARDABLE;
|
||||||
|
if (doDecodeOnDraw)
|
||||||
|
containerFlags |= imgIContainer::INIT_FLAG_DECODE_ON_DRAW;
|
||||||
|
if (mIsMultiPartChannel)
|
||||||
|
containerFlags |= imgIContainer::INIT_FLAG_MULTIPART;
|
||||||
|
|
||||||
|
// Create and initialize the imgContainer. This instantiates a decoder behind
|
||||||
|
// the scenes, so if we don't have a decoder for this mimetype we'll find out
|
||||||
|
// about it here.
|
||||||
|
mImage = do_CreateInstance("@mozilla.org/image/container;3");
|
||||||
|
if (!mImage) {
|
||||||
|
this->Cancel(NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
rv = mImage->Init(this, mContentType.get(), containerFlags);
|
||||||
|
if (NS_FAILED(rv)) { // Probably bad mimetype
|
||||||
|
|
||||||
|
// There's no reason to keep the image around. Save memory.
|
||||||
|
//
|
||||||
|
// XXXbholley - This is also here because I'm not sure we've found
|
||||||
|
// all the consumers who (incorrectly) check whether the container
|
||||||
|
// is null to determine things like size availability (they should
|
||||||
|
// be checking the image status instead).
|
||||||
|
mImage = nsnull;
|
||||||
|
|
||||||
|
this->Cancel(rv);
|
||||||
|
return NS_BINDING_ABORTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = mDecoder->Init(static_cast<imgILoad*>(this));
|
// WriteToContainer always consumes everything it gets
|
||||||
|
PRUint32 bytesRead;
|
||||||
|
rv = inStr->ReadSegments(imgContainer::WriteToContainer,
|
||||||
|
static_cast<void*>(mImage),
|
||||||
|
count, &bytesRead);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
PR_LOG(gImgLog, PR_LOG_WARNING,
|
PR_LOG(gImgLog, PR_LOG_WARNING,
|
||||||
("[this=%p] imgRequest::OnDataAvailable -- mDecoder->Init failed\n", this));
|
("[this=%p] imgRequest::OnDataAvailable -- "
|
||||||
|
"copy to container failed\n", this));
|
||||||
this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
|
this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
|
||||||
|
|
||||||
return NS_BINDING_ABORTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mDecoder) {
|
|
||||||
PR_LOG(gImgLog, PR_LOG_WARNING,
|
|
||||||
("[this=%p] imgRequest::OnDataAvailable -- no decoder\n", this));
|
|
||||||
|
|
||||||
this->Cancel(NS_IMAGELIB_ERROR_NO_DECODER);
|
|
||||||
|
|
||||||
return NS_BINDING_ABORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRUint32 wrote;
|
|
||||||
nsresult rv = mDecoder->WriteFrom(inStr, count, &wrote);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
PR_LOG(gImgLog, PR_LOG_WARNING,
|
|
||||||
("[this=%p] imgRequest::OnDataAvailable -- mDecoder->WriteFrom failed\n", this));
|
|
||||||
|
|
||||||
this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
|
|
||||||
|
|
||||||
return NS_BINDING_ABORTED;
|
return NS_BINDING_ABORTED;
|
||||||
}
|
}
|
||||||
|
NS_ABORT_IF_FALSE(bytesRead == count, "WriteToContainer should consume everything!");
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -1036,6 +1093,7 @@ imgRequest::SniffMimeType(const char *buf, PRUint32 len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** nsIInterfaceRequestor methods **/
|
/** nsIInterfaceRequestor methods **/
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Stuart Parmenter <pavlov@netscape.com>
|
* Stuart Parmenter <pavlov@netscape.com>
|
||||||
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -40,8 +41,6 @@
|
||||||
#ifndef imgRequest_h__
|
#ifndef imgRequest_h__
|
||||||
#define imgRequest_h__
|
#define imgRequest_h__
|
||||||
|
|
||||||
#include "imgILoad.h"
|
|
||||||
|
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "imgIDecoder.h"
|
#include "imgIDecoder.h"
|
||||||
#include "imgIDecoderObserver.h"
|
#include "imgIDecoderObserver.h"
|
||||||
|
@ -67,16 +66,13 @@ class imgRequestProxy;
|
||||||
class imgCacheEntry;
|
class imgCacheEntry;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
onStartRequest = PR_BIT(0),
|
stateRequestStarted = PR_BIT(0),
|
||||||
onStartDecode = PR_BIT(1),
|
stateHasSize = PR_BIT(1),
|
||||||
onStartContainer = PR_BIT(2),
|
stateDecodeStarted = PR_BIT(2),
|
||||||
onStopContainer = PR_BIT(3),
|
stateRequestStopped = PR_BIT(4)
|
||||||
onStopDecode = PR_BIT(4),
|
|
||||||
onStopRequest = PR_BIT(5)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class imgRequest : public imgILoad,
|
class imgRequest : public imgIDecoderObserver,
|
||||||
public imgIDecoderObserver,
|
|
||||||
public nsIStreamListener,
|
public nsIStreamListener,
|
||||||
public nsSupportsWeakReference,
|
public nsSupportsWeakReference,
|
||||||
public nsIChannelEventSink,
|
public nsIChannelEventSink,
|
||||||
|
@ -115,6 +111,8 @@ public:
|
||||||
// won't be sufficient.
|
// won't be sufficient.
|
||||||
void CancelAndAbort(nsresult aStatus);
|
void CancelAndAbort(nsresult aStatus);
|
||||||
|
|
||||||
|
nsresult GetImage(imgIContainer **aImage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class imgCacheEntry;
|
friend class imgCacheEntry;
|
||||||
friend class imgRequestProxy;
|
friend class imgRequestProxy;
|
||||||
|
@ -169,8 +167,10 @@ private:
|
||||||
// try to update or modify the image cache.
|
// try to update or modify the image cache.
|
||||||
void SetIsInCache(PRBool cacheable);
|
void SetIsInCache(PRBool cacheable);
|
||||||
|
|
||||||
|
// Update the cache entry size based on the image container
|
||||||
|
void UpdateCacheEntrySize();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_DECL_IMGILOAD
|
|
||||||
NS_DECL_IMGIDECODEROBSERVER
|
NS_DECL_IMGIDECODEROBSERVER
|
||||||
NS_DECL_IMGICONTAINEROBSERVER
|
NS_DECL_IMGICONTAINEROBSERVER
|
||||||
NS_DECL_NSISTREAMLISTENER
|
NS_DECL_NSISTREAMLISTENER
|
||||||
|
@ -186,7 +186,6 @@ private:
|
||||||
nsCOMPtr<nsIURI> mKeyURI;
|
nsCOMPtr<nsIURI> mKeyURI;
|
||||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
nsCOMPtr<imgIDecoder> mDecoder;
|
|
||||||
nsCOMPtr<nsIProperties> mProperties;
|
nsCOMPtr<nsIProperties> mProperties;
|
||||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||||
nsCOMPtr<nsIChannel> mChannel;
|
nsCOMPtr<nsIChannel> mChannel;
|
||||||
|
@ -210,7 +209,6 @@ private:
|
||||||
|
|
||||||
PRPackedBool mIsMultiPartChannel : 1;
|
PRPackedBool mIsMultiPartChannel : 1;
|
||||||
PRPackedBool mLoading : 1;
|
PRPackedBool mLoading : 1;
|
||||||
PRPackedBool mProcessing : 1;
|
|
||||||
PRPackedBool mHadLastPart : 1;
|
PRPackedBool mHadLastPart : 1;
|
||||||
PRPackedBool mGotData : 1;
|
PRPackedBool mGotData : 1;
|
||||||
PRPackedBool mIsInCache : 1;
|
PRPackedBool mIsInCache : 1;
|
||||||
|
|
|
@ -64,7 +64,9 @@ imgRequestProxy::imgRequestProxy() :
|
||||||
mLoadFlags(nsIRequest::LOAD_NORMAL),
|
mLoadFlags(nsIRequest::LOAD_NORMAL),
|
||||||
mCanceled(PR_FALSE),
|
mCanceled(PR_FALSE),
|
||||||
mIsInLoadGroup(PR_FALSE),
|
mIsInLoadGroup(PR_FALSE),
|
||||||
mListenerIsStrongRef(PR_FALSE)
|
mListenerIsStrongRef(PR_FALSE),
|
||||||
|
mShouldRequestDecode(PR_FALSE),
|
||||||
|
mLockHeld(PR_FALSE)
|
||||||
{
|
{
|
||||||
/* member initializers and constructor code */
|
/* member initializers and constructor code */
|
||||||
|
|
||||||
|
@ -75,6 +77,10 @@ imgRequestProxy::~imgRequestProxy()
|
||||||
/* destructor code */
|
/* destructor code */
|
||||||
NS_PRECONDITION(!mListener, "Someone forgot to properly cancel this request!");
|
NS_PRECONDITION(!mListener, "Someone forgot to properly cancel this request!");
|
||||||
|
|
||||||
|
// Unlock the image if we're holding a lock on it
|
||||||
|
if (mLockHeld && mOwner)
|
||||||
|
UnlockImage();
|
||||||
|
|
||||||
// Explicitly set mListener to null to ensure that the RemoveProxy
|
// Explicitly set mListener to null to ensure that the RemoveProxy
|
||||||
// call below can't send |this| to an arbitrary listener while |this|
|
// call below can't send |this| to an arbitrary listener while |this|
|
||||||
// is being destroyed. This is all belt-and-suspenders in view of the
|
// is being destroyed. This is all belt-and-suspenders in view of the
|
||||||
|
@ -129,6 +135,16 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
|
||||||
if (mCanceled)
|
if (mCanceled)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
|
// Were we decoded before?
|
||||||
|
PRBool wasDecoded = PR_FALSE;
|
||||||
|
if (mOwner->GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE)
|
||||||
|
wasDecoded = PR_TRUE;
|
||||||
|
|
||||||
|
// If we're holding a lock, unlock the old image
|
||||||
|
PRBool wasLocked = mLockHeld;
|
||||||
|
if (mLockHeld)
|
||||||
|
UnlockImage();
|
||||||
|
|
||||||
// Passing false to aNotify means that mListener will still get
|
// Passing false to aNotify means that mListener will still get
|
||||||
// OnStopRequest, if needed.
|
// OnStopRequest, if needed.
|
||||||
mOwner->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER, PR_FALSE);
|
mOwner->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER, PR_FALSE);
|
||||||
|
@ -137,6 +153,14 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
|
||||||
|
|
||||||
mOwner->AddProxy(this);
|
mOwner->AddProxy(this);
|
||||||
|
|
||||||
|
// If we were decoded, request a decode on the new image
|
||||||
|
if (wasDecoded)
|
||||||
|
RequestDecode();
|
||||||
|
|
||||||
|
// If we were locked, apply the lock here
|
||||||
|
if (wasLocked)
|
||||||
|
LockImage();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +266,74 @@ NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* void requestDecode (); */
|
||||||
|
NS_IMETHODIMP
|
||||||
|
imgRequestProxy::RequestDecode()
|
||||||
|
{
|
||||||
|
if (!mOwner)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
// See if we can get the image
|
||||||
|
nsCOMPtr<imgIContainer> container;
|
||||||
|
nsresult rv = mOwner->GetImage(getter_AddRefs(container));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
// If we've got the container, just forward along the request
|
||||||
|
if (container)
|
||||||
|
return container->RequestDecode();
|
||||||
|
|
||||||
|
// Otherwise, flag that we should do it when the container is ready
|
||||||
|
mShouldRequestDecode = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void lockImage (); */
|
||||||
|
NS_IMETHODIMP
|
||||||
|
imgRequestProxy::LockImage()
|
||||||
|
{
|
||||||
|
if (!mOwner)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
// Flag that we're holding a lock
|
||||||
|
NS_ABORT_IF_FALSE(!mLockHeld, "Only call lockImage once per imgIRequest!");
|
||||||
|
mLockHeld = PR_TRUE;
|
||||||
|
|
||||||
|
// If we've got the container, forward along the request. If we don't, well
|
||||||
|
// do it in OnStartContainer.
|
||||||
|
nsCOMPtr<imgIContainer> container;
|
||||||
|
nsresult rv = mOwner->GetImage(getter_AddRefs(container));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
if (container)
|
||||||
|
return container->LockImage();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void unlockImage (); */
|
||||||
|
NS_IMETHODIMP
|
||||||
|
imgRequestProxy::UnlockImage()
|
||||||
|
{
|
||||||
|
if (!mOwner)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
// Flag that we're not holding a lock
|
||||||
|
NS_ABORT_IF_FALSE(mLockHeld, "calling unlock but not locked!");
|
||||||
|
mLockHeld = PR_FALSE;
|
||||||
|
|
||||||
|
// If we've got the container, forward along the request. If we don't, it
|
||||||
|
// doesn't matter.
|
||||||
|
nsCOMPtr<imgIContainer> container;
|
||||||
|
nsresult rv = mOwner->GetImage(getter_AddRefs(container));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
if (container)
|
||||||
|
return container->UnlockImage();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* void suspend (); */
|
/* void suspend (); */
|
||||||
NS_IMETHODIMP imgRequestProxy::Suspend()
|
NS_IMETHODIMP imgRequestProxy::Suspend()
|
||||||
{
|
{
|
||||||
|
@ -458,6 +550,16 @@ void imgRequestProxy::OnStartContainer(imgIContainer *image)
|
||||||
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
|
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
|
||||||
mListener->OnStartContainer(this, image);
|
mListener->OnStartContainer(this, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request a decode if we said we should
|
||||||
|
if (mShouldRequestDecode) {
|
||||||
|
image->RequestDecode();
|
||||||
|
mShouldRequestDecode = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock if we said we should
|
||||||
|
if (mLockHeld)
|
||||||
|
image->LockImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void imgRequestProxy::OnStartFrame(PRUint32 frame)
|
void imgRequestProxy::OnStartFrame(PRUint32 frame)
|
||||||
|
@ -515,6 +617,18 @@ void imgRequestProxy::OnStopDecode(nsresult status, const PRUnichar *statusArg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void imgRequestProxy::OnDiscard()
|
||||||
|
{
|
||||||
|
LOG_FUNC(gImgLog, "imgRequestProxy::OnDiscard");
|
||||||
|
|
||||||
|
if (mListener && !mCanceled) {
|
||||||
|
// Hold a ref to the listener while we call it, just in case.
|
||||||
|
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
|
||||||
|
mListener->OnDiscard(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void imgRequestProxy::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
void imgRequestProxy::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||||
|
|
|
@ -116,6 +116,7 @@ protected:
|
||||||
void OnStopFrame (PRUint32 aFrame);
|
void OnStopFrame (PRUint32 aFrame);
|
||||||
void OnStopContainer (imgIContainer *aContainer);
|
void OnStopContainer (imgIContainer *aContainer);
|
||||||
void OnStopDecode (nsresult status, const PRUnichar *statusArg);
|
void OnStopDecode (nsresult status, const PRUnichar *statusArg);
|
||||||
|
void OnDiscard ();
|
||||||
|
|
||||||
/* non-virtual imgIContainerObserver methods */
|
/* non-virtual imgIContainerObserver methods */
|
||||||
void FrameChanged(imgIContainer *aContainer, nsIntRect * aDirtyRect);
|
void FrameChanged(imgIContainer *aContainer, nsIntRect * aDirtyRect);
|
||||||
|
@ -155,4 +156,6 @@ private:
|
||||||
PRPackedBool mCanceled;
|
PRPackedBool mCanceled;
|
||||||
PRPackedBool mIsInLoadGroup;
|
PRPackedBool mIsInLoadGroup;
|
||||||
PRPackedBool mListenerIsStrongRef;
|
PRPackedBool mListenerIsStrongRef;
|
||||||
|
PRPackedBool mShouldRequestDecode;
|
||||||
|
PRPackedBool mLockHeld;
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "ImageErrors.h"
|
#include "ImageErrors.h"
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "imgILoad.h"
|
|
||||||
#include "imgIDecoder.h"
|
#include "imgIDecoder.h"
|
||||||
#include "imgIEncoder.h"
|
#include "imgIEncoder.h"
|
||||||
#include "imgIDecoderObserver.h"
|
#include "imgIDecoderObserver.h"
|
||||||
|
@ -53,131 +52,7 @@
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "nsStreamUtils.h"
|
#include "nsStreamUtils.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
|
#include "imgContainer.h"
|
||||||
|
|
||||||
/* ========== Utility classes ========== */
|
|
||||||
|
|
||||||
|
|
||||||
class HelperLoader : public imgILoad,
|
|
||||||
public imgIDecoderObserver,
|
|
||||||
public nsSupportsWeakReference
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
NS_DECL_IMGILOAD
|
|
||||||
NS_DECL_IMGIDECODEROBSERVER
|
|
||||||
NS_DECL_IMGICONTAINEROBSERVER
|
|
||||||
HelperLoader(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsCOMPtr<imgIContainer> mContainer;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS4 (HelperLoader, imgILoad, imgIDecoderObserver, imgIContainerObserver, nsISupportsWeakReference)
|
|
||||||
|
|
||||||
HelperLoader::HelperLoader (void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgILoad::image getter */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::GetImage(imgIContainer **aImage)
|
|
||||||
{
|
|
||||||
*aImage = mContainer;
|
|
||||||
NS_IF_ADDREF (*aImage);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgILoad::image setter */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::SetImage(imgIContainer *aImage)
|
|
||||||
{
|
|
||||||
mContainer = aImage;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgILoad::isMultiPartChannel getter */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::GetIsMultiPartChannel(PRBool *aIsMultiPartChannel)
|
|
||||||
{
|
|
||||||
*aIsMultiPartChannel = PR_FALSE;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStartRequest() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStartRequest(imgIRequest *aRequest)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStartDecode() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStartDecode(imgIRequest *aRequest)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStartContainer() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer
|
|
||||||
*aContainer)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStartFrame() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStartFrame(imgIRequest *aRequest, PRUint32 aFrame)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onDataAvailable() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame, const nsIntRect * aRect)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStopFrame() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStopContainer() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStopContainer(imgIRequest *aRequest, imgIContainer
|
|
||||||
*aContainer)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStopDecode() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStopDecode(imgIRequest *aRequest, nsresult status, const
|
|
||||||
PRUnichar *statusArg)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement imgIDecoderObserver::onStopRequest() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* implement imgIContainerObserver::frameChanged() */
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HelperLoader::FrameChanged(imgIContainer *aContainer, nsIntRect * aDirtyRect)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ========== imgITools implementation ========== */
|
/* ========== imgITools implementation ========== */
|
||||||
|
|
||||||
|
@ -202,24 +77,19 @@ NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
// Get an image decoder for our media type
|
NS_ENSURE_ARG_POINTER(aInStr);
|
||||||
nsCAutoString decoderCID(
|
// If the caller didn't provide a container, create one
|
||||||
NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + aMimeType);
|
if (!*aContainer) {
|
||||||
|
NS_NEWXPCOM(*aContainer, imgContainer);
|
||||||
nsCOMPtr<imgIDecoder> decoder = do_CreateInstance(decoderCID.get());
|
if (!*aContainer)
|
||||||
if (!decoder)
|
|
||||||
return NS_IMAGELIB_ERROR_NO_DECODER;
|
|
||||||
|
|
||||||
// Init the decoder, we use a small utility class here.
|
|
||||||
nsCOMPtr<imgILoad> loader = new HelperLoader();
|
|
||||||
if (!loader)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
NS_ADDREF(*aContainer);
|
||||||
|
}
|
||||||
|
|
||||||
// If caller provided an existing container, use it.
|
// Initialize the container. If we're using the one from the caller, we
|
||||||
if (*aContainer)
|
// require that it not be initialized
|
||||||
loader->SetImage(*aContainer);
|
nsCString mimeType(aMimeType);
|
||||||
|
rv = (*aContainer)->Init(nsnull, mimeType.get(), imgIContainer::INIT_FLAG_NONE);
|
||||||
rv = decoder->Init(loader);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> inStream = aInStr;
|
nsCOMPtr<nsIInputStream> inStream = aInStr;
|
||||||
|
@ -230,24 +100,25 @@ NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
|
||||||
inStream = bufStream;
|
inStream = bufStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Figure out how much data we've been passed
|
||||||
PRUint32 length;
|
PRUint32 length;
|
||||||
rv = inStream->Available(&length);
|
rv = inStream->Available(&length);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
PRUint32 written;
|
// Send the source data to the container. WriteToContainer always
|
||||||
rv = decoder->WriteFrom(inStream, length, &written);
|
// consumes everything it gets.
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
PRUint32 bytesRead;
|
||||||
if (written != length)
|
rv = inStream->ReadSegments(imgContainer::WriteToContainer,
|
||||||
NS_WARNING("decoder didn't eat all of its vegetables");
|
static_cast<void*>(*aContainer),
|
||||||
rv = decoder->Flush();
|
length, &bytesRead);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = decoder->Close();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// If caller didn't provide an existing container, return the new one.
|
|
||||||
if (!*aContainer)
|
|
||||||
loader->GetImage(aContainer);
|
|
||||||
|
|
||||||
|
// Let the container know we've sent all the data
|
||||||
|
rv = (*aContainer)->SourceDataComplete();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// All done
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +161,8 @@ NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
|
||||||
|
|
||||||
// Use frame 0 from the image container.
|
// Use frame 0 from the image container.
|
||||||
nsRefPtr<gfxImageSurface> frame;
|
nsRefPtr<gfxImageSurface> frame;
|
||||||
rv = aContainer->CopyCurrentFrame(getter_AddRefs(frame));
|
rv = aContainer->CopyFrame(imgIContainer::FRAME_CURRENT, PR_TRUE,
|
||||||
|
getter_AddRefs(frame));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
|
@ -44,7 +44,8 @@ relativesrcdir = modules/libpr0n/test/mochitest
|
||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
_TEST_FILES = test_bug399925.html \
|
_TEST_FILES = imgutils.js \
|
||||||
|
test_bug399925.html \
|
||||||
bug399925.gif \
|
bug399925.gif \
|
||||||
bug468160.sjs \
|
bug468160.sjs \
|
||||||
test_bug468160.html \
|
test_bug468160.html \
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Helper file for shared image functionality
|
||||||
|
//
|
||||||
|
// Note that this is use by tests elsewhere in the source tree. When in doubt,
|
||||||
|
// check mxr before removing or changing functionality.
|
||||||
|
|
||||||
|
// Helper function to determine if the frame is decoded for a given image id
|
||||||
|
function isFrameDecoded(id)
|
||||||
|
{
|
||||||
|
return (getImageStatus(id) &
|
||||||
|
Components.interfaces.imgIRequest.STATUS_FRAME_COMPLETE)
|
||||||
|
? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to determine if the image is loaded for a given image id
|
||||||
|
function isImageLoaded(id)
|
||||||
|
{
|
||||||
|
return (getImageStatus(id) &
|
||||||
|
Components.interfaces.imgIRequest.STATUS_LOAD_COMPLETE)
|
||||||
|
? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get the status flags of an image
|
||||||
|
function getImageStatus(id)
|
||||||
|
{
|
||||||
|
// Escalate
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
|
||||||
|
// Get the image
|
||||||
|
var img = document.getElementById(id);
|
||||||
|
|
||||||
|
// QI the image to nsImageLoadingContent
|
||||||
|
img.QueryInterface(Components.interfaces.nsIImageLoadingContent);
|
||||||
|
|
||||||
|
// Get the request
|
||||||
|
var request = img.getRequest(Components.interfaces
|
||||||
|
.nsIImageLoadingContent
|
||||||
|
.CURRENT_REQUEST);
|
||||||
|
|
||||||
|
// Return the status
|
||||||
|
return request.imageStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forces a synchronous decode of an image by drawing it to a canvas. Only
|
||||||
|
// really meaningful if the image is fully loaded first
|
||||||
|
function forceDecode(id)
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
|
||||||
|
// Get the image
|
||||||
|
var img = document.getElementById(id);
|
||||||
|
|
||||||
|
// Make a new canvas
|
||||||
|
var canvas = document.createElement("canvas");
|
||||||
|
|
||||||
|
// Draw the image to the canvas. This forces a synchronous decode
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Functions to facilitate getting/setting the discard timer pref
|
||||||
|
//
|
||||||
|
// Don't forget to reset the pref to the original value!
|
||||||
|
//
|
||||||
|
// Null indicates no pref set
|
||||||
|
|
||||||
|
const DISCARD_BRANCH_NAME = "image.cache.";
|
||||||
|
const DISCARD_PREF_NAME = "discard_timer_ms";
|
||||||
|
|
||||||
|
function setDiscardTimerPref(timeMS)
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrefService);
|
||||||
|
var branch = prefService.getBranch(DISCARD_BRANCH_NAME);
|
||||||
|
if (timeMS != null)
|
||||||
|
branch.setIntPref(DISCARD_PREF_NAME, timeMS);
|
||||||
|
else if (branch.prefHasUserValue(DISCARD_PREF_NAME))
|
||||||
|
branch.clearUserPref(DISCARD_PREF_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDiscardTimerPref()
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrefService);
|
||||||
|
var branch = prefService.getBranch(DISCARD_BRANCH_NAME);
|
||||||
|
if (branch.prefHasUserValue(DISCARD_PREF_NAME))
|
||||||
|
return branch.getIntPref("discard_timeout_ms");
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -6,19 +6,36 @@
|
||||||
<body>
|
<body>
|
||||||
<img id="image1">
|
<img id="image1">
|
||||||
<script>
|
<script>
|
||||||
// This loads a externally specified image, waits 100ms, and then triggers the
|
// This loads a externally specified image, forces a draw (in case of
|
||||||
// reftest snapshot. This allows the animation on the page to complete.
|
// decode-on-draw), waits 100ms, and then triggers the reftest snapshot.
|
||||||
|
// This allows the animation on the page to complete.
|
||||||
//
|
//
|
||||||
// Use as "delaytest.html?animation.png"
|
// Use as "delaytest.html?animation.png"
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Get the image URL from our URL
|
||||||
|
var imgURL = document.location.search.substr(1);
|
||||||
|
|
||||||
|
// Load the image
|
||||||
|
var img = document.images[0];
|
||||||
|
img.src = imgURL;
|
||||||
|
img.onload = forceDecode;
|
||||||
|
|
||||||
|
function forceDecode() {
|
||||||
|
|
||||||
|
// We need to force drawing of the image in an invisible context
|
||||||
|
var canvas = document.createElement("canvas");
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
|
// We've force the decode. start the timer to trigger the reftest
|
||||||
|
startTimer();
|
||||||
|
}
|
||||||
|
|
||||||
function startTimer() {
|
function startTimer() {
|
||||||
const delay = 100;
|
const delay = 100;
|
||||||
setTimeout("document.documentElement.className = '';", delay);
|
setTimeout("document.documentElement.className = '';", delay);
|
||||||
}
|
}
|
||||||
var imgURL = document.location.search.substr(1);
|
|
||||||
var img = document.images[0];
|
|
||||||
img.src = imgURL;
|
|
||||||
img.onload = startTimer;
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -382,6 +382,7 @@ imgFile = do_get_file(imgName);
|
||||||
|
|
||||||
istream = getFileInputStream(imgFile);
|
istream = getFileInputStream(imgFile);
|
||||||
do_check_eq(istream.available(), 17759);
|
do_check_eq(istream.available(), 17759);
|
||||||
|
var errsrc = "none";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
outParam = { value: null };
|
outParam = { value: null };
|
||||||
|
@ -394,12 +395,15 @@ try {
|
||||||
istream = imgTools.encodeImage(container, "image/png");
|
istream = imgTools.encodeImage(container, "image/png");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
err = e;
|
||||||
|
errsrc = "encode";
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
err = e;
|
||||||
|
errsrc = "decode";
|
||||||
}
|
}
|
||||||
|
|
||||||
checkExpectedError(/NS_ERROR_ILLEGAL_VALUE/, err);
|
do_check_eq(errsrc, "decode");
|
||||||
|
checkExpectedError(/NS_ERROR_FAILURE/, err);
|
||||||
|
|
||||||
|
|
||||||
/* ========== end ========== */
|
/* ========== end ========== */
|
||||||
|
|
|
@ -161,6 +161,12 @@ nsAlertsIconListener::OnStopRequest(imgIRequest* aRequest,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsAlertsIconListener::OnDiscard(imgIRequest *aRequest)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsAlertsIconListener::OnStopFrame(imgIRequest* aRequest,
|
nsAlertsIconListener::OnStopFrame(imgIRequest* aRequest,
|
||||||
PRUint32 aFrame)
|
PRUint32 aFrame)
|
||||||
|
|
|
@ -432,7 +432,9 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<gfxImageSurface> currentFrame;
|
nsRefPtr<gfxImageSurface> currentFrame;
|
||||||
if (NS_FAILED(image->CopyCurrentFrame(getter_AddRefs(currentFrame))))
|
if (NS_FAILED(image->CopyFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(currentFrame))))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PRInt32 height = currentFrame->Height();
|
PRInt32 height = currentFrame->Height();
|
||||||
|
|
|
@ -306,6 +306,10 @@ NS_IMETHODIMP
|
||||||
nsMenuItemIconX::OnStartContainer(imgIRequest* aRequest,
|
nsMenuItemIconX::OnStartContainer(imgIRequest* aRequest,
|
||||||
imgIContainer* aContainer)
|
imgIContainer* aContainer)
|
||||||
{
|
{
|
||||||
|
// Request a decode
|
||||||
|
NS_ABORT_IF_FALSE(aContainer, "who sent the notification then?");
|
||||||
|
aContainer->RequestDecode();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +348,9 @@ nsMenuItemIconX::OnStopFrame(imgIRequest* aRequest,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
nsRefPtr<gfxImageSurface> image;
|
nsRefPtr<gfxImageSurface> image;
|
||||||
imageContainer->CopyCurrentFrame(getter_AddRefs(image));
|
imageContainer->CopyFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_NONE,
|
||||||
|
getter_AddRefs(image));
|
||||||
|
|
||||||
PRInt32 height = image->Height();
|
PRInt32 height = image->Height();
|
||||||
PRInt32 stride = image->Stride();
|
PRInt32 stride = image->Stride();
|
||||||
|
@ -478,3 +484,9 @@ nsMenuItemIconX::OnStopRequest(imgIRequest* aRequest,
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsMenuItemIconX::OnDiscard(imgIRequest* aRequest)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -69,7 +69,9 @@ GdkPixbuf*
|
||||||
nsImageToPixbuf::ImageToPixbuf(imgIContainer* aImage)
|
nsImageToPixbuf::ImageToPixbuf(imgIContainer* aImage)
|
||||||
{
|
{
|
||||||
nsRefPtr<gfxImageSurface> frame;
|
nsRefPtr<gfxImageSurface> frame;
|
||||||
aImage->CopyCurrentFrame(getter_AddRefs(frame));
|
aImage->CopyFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(frame));
|
||||||
|
|
||||||
return ImgSurfaceToPixbuf(frame, frame->Width(), frame->Height());
|
return ImgSurfaceToPixbuf(frame, frame->Width(), frame->Height());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1619,7 +1619,9 @@ NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<gfxImageSurface> frame;
|
nsRefPtr<gfxImageSurface> frame;
|
||||||
aCursor->CopyCurrentFrame(getter_AddRefs(frame));
|
aCursor->CopyFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(frame));
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,9 @@ nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap
|
||||||
*outBitmap = nsnull;
|
*outBitmap = nsnull;
|
||||||
|
|
||||||
nsRefPtr<gfxImageSurface> frame;
|
nsRefPtr<gfxImageSurface> frame;
|
||||||
nsresult rv = inImage->CopyCurrentFrame(getter_AddRefs(frame));
|
nsresult rv = inImage->CopyFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(frame));
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
|
|
@ -692,7 +692,9 @@ nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
|
||||||
|
|
||||||
// Get the image data
|
// Get the image data
|
||||||
nsRefPtr<gfxImageSurface> frame;
|
nsRefPtr<gfxImageSurface> frame;
|
||||||
aContainer->CopyCurrentFrame(getter_AddRefs(frame));
|
aContainer->CopyFrame(imgIContainer::FRAME_CURRENT,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE,
|
||||||
|
getter_AddRefs(frame));
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
|
|
@ -601,7 +601,8 @@ nsBaseDragService::DrawDragForImage(nsPresContext* aPresContext,
|
||||||
gfxMatrix scale =
|
gfxMatrix scale =
|
||||||
gfxMatrix().Scale(srcSize.width/outRect.Width(), srcSize.height/outRect.Height());
|
gfxMatrix().Scale(srcSize.width/outRect.Width(), srcSize.height/outRect.Height());
|
||||||
nsIntRect imgSize(0, 0, srcSize.width, srcSize.height);
|
nsIntRect imgSize(0, 0, srcSize.width, srcSize.height);
|
||||||
imgContainer->Draw(ctx, gfxPattern::FILTER_GOOD, scale, outRect, imgSize);
|
imgContainer->Draw(ctx, gfxPattern::FILTER_GOOD, scale, outRect, imgSize,
|
||||||
|
imgIContainer::FLAG_SYNC_DECODE);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
} else {
|
} else {
|
||||||
return aCanvas->RenderContexts(ctx, gfxPattern::FILTER_GOOD);
|
return aCanvas->RenderContexts(ctx, gfxPattern::FILTER_GOOD);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче