2010-08-22 19:30:45 -07:00
|
|
|
|
|
|
|
/* -*- 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
|
|
|
|
* the Mozilla Foundation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2010.
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* 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 "Decoder.h"
|
2010-09-12 08:22:31 -07:00
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIConsoleService.h"
|
2010-12-20 08:21:59 -08:00
|
|
|
#include "nsIScriptError.h"
|
2010-08-22 19:30:45 -07:00
|
|
|
|
|
|
|
namespace mozilla {
|
2012-01-06 08:02:27 -08:00
|
|
|
namespace image {
|
2010-08-22 19:30:45 -07:00
|
|
|
|
2011-09-29 06:17:13 -07:00
|
|
|
Decoder::Decoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
|
|
|
|
: mImage(aImage)
|
|
|
|
, mObserver(aObserver)
|
|
|
|
, mDecodeFlags(0)
|
2012-01-02 12:23:41 -08:00
|
|
|
, mDecodeDone(false)
|
|
|
|
, mDataError(false)
|
2011-01-12 17:45:13 -08:00
|
|
|
, mFrameCount(0)
|
2010-09-12 08:22:27 -07:00
|
|
|
, mFailCode(NS_OK)
|
2010-08-22 19:30:46 -07:00
|
|
|
, mInitialized(false)
|
2010-08-22 19:30:46 -07:00
|
|
|
, mSizeDecode(false)
|
2010-08-22 19:30:46 -07:00
|
|
|
, mInFrame(false)
|
2011-11-09 13:39:16 -08:00
|
|
|
, mIsAnimated(false)
|
2010-08-22 19:30:45 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Decoder::~Decoder()
|
|
|
|
{
|
2010-08-22 19:30:46 -07:00
|
|
|
NS_WARN_IF_FALSE(!mInFrame, "Shutting down decoder mid-frame!");
|
2010-08-22 19:30:45 -07:00
|
|
|
mInitialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common implementation of the decoder interface.
|
|
|
|
*/
|
|
|
|
|
2010-09-12 08:22:31 -07:00
|
|
|
void
|
2011-09-27 09:24:03 -07:00
|
|
|
Decoder::Init()
|
2010-08-22 19:30:45 -07:00
|
|
|
{
|
2010-08-22 19:30:46 -07:00
|
|
|
// No re-initializing
|
2011-09-27 09:24:03 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
|
2010-08-22 19:30:45 -07:00
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// Fire OnStartDecode at init time to support bug 512435
|
|
|
|
if (!IsSizeDecode() && mObserver)
|
|
|
|
mObserver->OnStartDecode(nsnull);
|
|
|
|
|
2010-08-22 19:30:45 -07:00
|
|
|
// Implementation-specific initialization
|
2010-09-12 08:22:28 -07:00
|
|
|
InitInternal();
|
2010-08-22 19:30:45 -07:00
|
|
|
mInitialized = true;
|
|
|
|
}
|
|
|
|
|
2011-08-25 13:09:01 -07:00
|
|
|
// Initializes a decoder whose aImage and aObserver is already being used by a
|
|
|
|
// parent decoder
|
2011-09-27 09:24:03 -07:00
|
|
|
void
|
|
|
|
Decoder::InitSharedDecoder()
|
2011-08-25 13:09:01 -07:00
|
|
|
{
|
|
|
|
// No re-initializing
|
2011-09-27 09:24:03 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
|
2011-08-25 13:09:01 -07:00
|
|
|
|
|
|
|
// Implementation-specific initialization
|
|
|
|
InitInternal();
|
|
|
|
mInitialized = true;
|
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:31 -07:00
|
|
|
void
|
2010-08-22 19:30:45 -07:00
|
|
|
Decoder::Write(const char* aBuffer, PRUint32 aCount)
|
|
|
|
{
|
2010-09-12 08:22:30 -07:00
|
|
|
// We're strict about decoder errors
|
2010-09-12 08:22:31 -07:00
|
|
|
NS_ABORT_IF_FALSE(!HasDecoderError(),
|
2010-09-12 08:22:30 -07:00
|
|
|
"Not allowed to make more decoder calls after error!");
|
|
|
|
|
|
|
|
// If a data error occured, just ignore future data
|
2010-09-12 08:22:31 -07:00
|
|
|
if (HasDataError())
|
2010-09-12 08:22:31 -07:00
|
|
|
return;
|
2010-09-12 08:22:30 -07:00
|
|
|
|
2010-08-22 19:30:45 -07:00
|
|
|
// Pass the data along to the implementation
|
2010-09-12 08:22:28 -07:00
|
|
|
WriteInternal(aBuffer, aCount);
|
2010-08-22 19:30:45 -07:00
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:31 -07:00
|
|
|
void
|
2010-08-22 19:30:45 -07:00
|
|
|
Decoder::Finish()
|
|
|
|
{
|
|
|
|
// Implementation-specific finalization
|
2010-09-12 08:22:31 -07:00
|
|
|
if (!HasError())
|
2010-09-12 08:22:30 -07:00
|
|
|
FinishInternal();
|
2010-09-12 08:22:30 -07:00
|
|
|
|
|
|
|
// If the implementation left us mid-frame, finish that up.
|
2010-09-12 08:22:31 -07:00
|
|
|
if (mInFrame && !HasDecoderError())
|
2010-09-12 08:22:30 -07:00
|
|
|
PostFrameStop();
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// If PostDecodeDone() has not been called, we need to sent teardown
|
|
|
|
// notifications.
|
2010-09-12 08:22:30 -07:00
|
|
|
if (!IsSizeDecode() && !mDecodeDone) {
|
2010-09-12 08:22:30 -07:00
|
|
|
|
2010-09-12 08:22:31 -07:00
|
|
|
// Log data errors to the error console
|
2010-12-20 08:21:59 -08:00
|
|
|
nsCOMPtr<nsIConsoleService> consoleService =
|
|
|
|
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
2011-12-21 13:51:29 -08:00
|
|
|
nsCOMPtr<nsIScriptError> errorObject =
|
2010-12-20 08:21:59 -08:00
|
|
|
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
|
|
|
|
|
|
|
|
if (consoleService && errorObject && !HasDecoderError()) {
|
2010-09-12 08:22:31 -07:00
|
|
|
nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
|
2011-09-29 06:17:13 -07:00
|
|
|
NS_ConvertASCIItoUTF16(mImage.GetURIString()));
|
2010-12-20 08:21:59 -08:00
|
|
|
|
2011-12-21 13:51:29 -08:00
|
|
|
if (NS_SUCCEEDED(errorObject->InitWithWindowID(
|
|
|
|
msg.get(),
|
|
|
|
NS_ConvertUTF8toUTF16(mImage.GetURIString()).get(),
|
|
|
|
nsnull, 0, 0, nsIScriptError::errorFlag,
|
|
|
|
"Image", mImage.InnerWindowID()
|
|
|
|
))) {
|
|
|
|
consoleService->LogMessage(errorObject);
|
|
|
|
}
|
2010-09-12 08:22:31 -07:00
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// If we only have a data error, see if things are worth salvaging
|
2011-09-29 06:17:13 -07:00
|
|
|
bool salvage = !HasDecoderError() && mImage.GetNumFrames();
|
2010-09-12 08:22:30 -07:00
|
|
|
|
|
|
|
// If we're salvaging, say we finished decoding
|
|
|
|
if (salvage)
|
2011-09-29 06:17:13 -07:00
|
|
|
mImage.DecodingComplete();
|
2010-09-12 08:22:30 -07:00
|
|
|
|
|
|
|
// Fire teardown notifications
|
2010-09-12 08:22:30 -07:00
|
|
|
if (mObserver) {
|
2011-09-29 06:17:13 -07:00
|
|
|
mObserver->OnStopContainer(nsnull, &mImage);
|
2010-09-12 08:22:30 -07:00
|
|
|
mObserver->OnStopDecode(nsnull, salvage ? NS_OK : NS_ERROR_FAILURE, nsnull);
|
2010-09-12 08:22:30 -07:00
|
|
|
}
|
|
|
|
}
|
2010-08-22 19:30:45 -07:00
|
|
|
}
|
|
|
|
|
2011-08-25 13:09:01 -07:00
|
|
|
void
|
|
|
|
Decoder::FinishSharedDecoder()
|
|
|
|
{
|
|
|
|
if (!HasError()) {
|
|
|
|
FinishInternal();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-24 13:40:45 -07:00
|
|
|
void
|
|
|
|
Decoder::FlushInvalidations()
|
|
|
|
{
|
2010-09-12 08:22:31 -07:00
|
|
|
NS_ABORT_IF_FALSE(!HasDecoderError(),
|
2010-09-12 08:22:30 -07:00
|
|
|
"Not allowed to make more decoder calls after error!");
|
|
|
|
|
2010-08-24 13:40:45 -07:00
|
|
|
// If we've got an empty invalidation rect, we have nothing to do
|
|
|
|
if (mInvalidRect.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Tell the image that it's been updated
|
2011-09-29 06:17:13 -07:00
|
|
|
mImage.FrameUpdated(mFrameCount - 1, mInvalidRect);
|
2010-08-24 13:40:45 -07:00
|
|
|
|
|
|
|
// Fire OnDataAvailable
|
|
|
|
if (mObserver) {
|
2011-11-24 15:23:19 -08:00
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// Bug 703231
|
|
|
|
// Because of high quality down sampling on mac we show scan lines while decoding.
|
|
|
|
// Bypass this problem by redrawing the border.
|
|
|
|
PRInt32 width;
|
|
|
|
PRInt32 height;
|
|
|
|
|
|
|
|
mImage.GetWidth(&width);
|
|
|
|
mImage.GetHeight(&height);
|
|
|
|
nsIntRect mImageBound(0, 0, width, height);
|
|
|
|
|
|
|
|
mInvalidRect.Inflate(1);
|
|
|
|
mInvalidRect = mInvalidRect.Intersect(mImageBound);
|
|
|
|
#endif
|
2011-09-29 06:17:13 -07:00
|
|
|
bool isCurrentFrame = mImage.GetCurrentFrameIndex() == (mFrameCount - 1);
|
2010-08-24 13:40:45 -07:00
|
|
|
mObserver->OnDataAvailable(nsnull, isCurrentFrame, &mInvalidRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear the invalidation rectangle
|
2011-04-18 20:07:23 -07:00
|
|
|
mInvalidRect.SetEmpty();
|
2010-08-24 13:40:45 -07:00
|
|
|
}
|
|
|
|
|
2010-08-22 19:30:45 -07:00
|
|
|
/*
|
|
|
|
* Hook stubs. Override these as necessary in decoder implementations.
|
|
|
|
*/
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
void Decoder::InitInternal() { }
|
|
|
|
void Decoder::WriteInternal(const char* aBuffer, PRUint32 aCount) { }
|
|
|
|
void Decoder::FinishInternal() { }
|
2010-08-22 19:30:45 -07:00
|
|
|
|
2010-08-22 19:30:46 -07:00
|
|
|
/*
|
|
|
|
* Progress Notifications
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
Decoder::PostSize(PRInt32 aWidth, PRInt32 aHeight)
|
|
|
|
{
|
|
|
|
// Validate
|
|
|
|
NS_ABORT_IF_FALSE(aWidth >= 0, "Width can't be negative!");
|
|
|
|
NS_ABORT_IF_FALSE(aHeight >= 0, "Height can't be negative!");
|
|
|
|
|
|
|
|
// Tell the image
|
2011-09-29 06:17:13 -07:00
|
|
|
mImage.SetSize(aWidth, aHeight);
|
2010-08-22 19:30:46 -07:00
|
|
|
|
|
|
|
// Notify the observer
|
|
|
|
if (mObserver)
|
2011-09-29 06:17:13 -07:00
|
|
|
mObserver->OnStartContainer(nsnull, &mImage);
|
2010-08-22 19:30:46 -07:00
|
|
|
}
|
|
|
|
|
2010-08-22 19:30:46 -07:00
|
|
|
void
|
|
|
|
Decoder::PostFrameStart()
|
|
|
|
{
|
|
|
|
// We shouldn't already be mid-frame
|
|
|
|
NS_ABORT_IF_FALSE(!mInFrame, "Starting new frame but not done with old one!");
|
|
|
|
|
2010-08-24 13:40:45 -07:00
|
|
|
// We should take care of any invalidation region when wrapping up the
|
|
|
|
// previous frame
|
|
|
|
NS_ABORT_IF_FALSE(mInvalidRect.IsEmpty(),
|
|
|
|
"Start image frame with non-empty invalidation region!");
|
|
|
|
|
2010-08-22 19:30:46 -07:00
|
|
|
// Update our state to reflect the new frame
|
|
|
|
mFrameCount++;
|
|
|
|
mInFrame = true;
|
|
|
|
|
|
|
|
// Decoder implementations should only call this method if they successfully
|
|
|
|
// appended the frame to the image. So mFrameCount should always match that
|
|
|
|
// reported by the Image.
|
2011-09-29 06:17:13 -07:00
|
|
|
NS_ABORT_IF_FALSE(mFrameCount == mImage.GetNumFrames(),
|
2010-08-22 19:30:46 -07:00
|
|
|
"Decoder frame count doesn't match image's!");
|
|
|
|
|
|
|
|
// Fire notification
|
|
|
|
if (mObserver)
|
|
|
|
mObserver->OnStartFrame(nsnull, mFrameCount - 1); // frame # is zero-indexed
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Decoder::PostFrameStop()
|
|
|
|
{
|
|
|
|
// We should be mid-frame
|
|
|
|
NS_ABORT_IF_FALSE(mInFrame, "Stopping frame when we didn't start one!");
|
|
|
|
|
|
|
|
// Update our state
|
|
|
|
mInFrame = false;
|
|
|
|
|
2010-08-25 13:11:09 -07:00
|
|
|
// Flush any invalidations before we finish the frame
|
|
|
|
FlushInvalidations();
|
|
|
|
|
2011-11-09 13:39:16 -08:00
|
|
|
// Fire notifications
|
|
|
|
if (mObserver) {
|
2010-08-22 19:30:46 -07:00
|
|
|
mObserver->OnStopFrame(nsnull, mFrameCount - 1); // frame # is zero-indexed
|
2011-11-09 13:39:16 -08:00
|
|
|
if (mFrameCount > 1 && !mIsAnimated) {
|
|
|
|
mIsAnimated = true;
|
|
|
|
mObserver->OnImageIsAnimated(nsnull);
|
|
|
|
}
|
|
|
|
}
|
2010-08-22 19:30:46 -07:00
|
|
|
}
|
|
|
|
|
2010-08-24 13:40:45 -07:00
|
|
|
void
|
|
|
|
Decoder::PostInvalidation(nsIntRect& aRect)
|
|
|
|
{
|
|
|
|
// We should be mid-frame
|
|
|
|
NS_ABORT_IF_FALSE(mInFrame, "Can't invalidate when not mid-frame!");
|
|
|
|
|
|
|
|
// Account for the new region
|
|
|
|
mInvalidRect.UnionRect(mInvalidRect, aRect);
|
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
void
|
|
|
|
Decoder::PostDecodeDone()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(!IsSizeDecode(), "Can't be done with decoding with size decode!");
|
|
|
|
NS_ABORT_IF_FALSE(!mInFrame, "Can't be done decoding if we're mid-frame!");
|
|
|
|
NS_ABORT_IF_FALSE(!mDecodeDone, "Decode already done!");
|
|
|
|
mDecodeDone = true;
|
|
|
|
|
2012-03-23 15:10:50 -07:00
|
|
|
// Set premult before DecodingComplete(), since DecodingComplete() calls Optimize()
|
|
|
|
int frames = GetFrameCount();
|
|
|
|
bool isNonPremult = GetDecodeFlags() & DECODER_NO_PREMULTIPLY_ALPHA;
|
|
|
|
for (int i = 0; i < frames; i++) {
|
|
|
|
mImage.SetFrameAsNonPremult(i, isNonPremult);
|
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// Notify
|
2011-09-29 06:17:13 -07:00
|
|
|
mImage.DecodingComplete();
|
2010-09-12 08:22:30 -07:00
|
|
|
if (mObserver) {
|
2011-09-29 06:17:13 -07:00
|
|
|
mObserver->OnStopContainer(nsnull, &mImage);
|
2010-09-12 08:22:30 -07:00
|
|
|
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:27 -07:00
|
|
|
void
|
|
|
|
Decoder::PostDataError()
|
|
|
|
{
|
|
|
|
mDataError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Decoder::PostDecoderError(nsresult aFailureCode)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(NS_FAILED(aFailureCode), "Not a failure code!");
|
|
|
|
|
|
|
|
mFailCode = aFailureCode;
|
|
|
|
|
|
|
|
// XXXbholley - we should report the image URI here, but imgContainer
|
|
|
|
// needs to know its URI first
|
|
|
|
NS_WARNING("Image decoding error - This is probably a bug!");
|
|
|
|
}
|
|
|
|
|
2012-01-06 08:02:27 -08:00
|
|
|
} // namespace image
|
2010-08-22 19:30:45 -07:00
|
|
|
} // namespace mozilla
|