2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2014-04-15 11:02:23 -07:00
|
|
|
// Must #include ImageLogging.h before any IPDL-generated files or other files that #include prlog.h
|
2012-04-03 14:57:22 -07:00
|
|
|
#include "ImageLogging.h"
|
2014-04-15 11:02:23 -07:00
|
|
|
|
|
|
|
#include "RasterImage.h"
|
|
|
|
|
|
|
|
#include "base/histogram.h"
|
|
|
|
#include "gfxPlatform.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsComponentManagerUtils.h"
|
2012-07-27 07:03:27 -07:00
|
|
|
#include "nsError.h"
|
2010-08-22 19:30:46 -07:00
|
|
|
#include "Decoder.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsAutoPtr.h"
|
2007-10-18 17:36:34 -07:00
|
|
|
#include "prenv.h"
|
2013-03-01 15:17:24 -08:00
|
|
|
#include "prsystem.h"
|
2012-08-19 12:33:25 -07:00
|
|
|
#include "ImageContainer.h"
|
2014-08-22 13:12:38 -07:00
|
|
|
#include "ImageRegion.h"
|
2012-08-19 12:33:25 -07:00
|
|
|
#include "Layers.h"
|
2013-01-10 19:38:34 -08:00
|
|
|
#include "nsPresContext.h"
|
2013-03-01 15:17:24 -08:00
|
|
|
#include "nsIThreadPool.h"
|
|
|
|
#include "nsXPCOMCIDInternal.h"
|
|
|
|
#include "nsIObserverService.h"
|
2014-09-19 14:53:29 -07:00
|
|
|
#include "SurfaceCache.h"
|
2013-07-15 11:38:59 -07:00
|
|
|
#include "FrameAnimator.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-22 19:30:45 -07:00
|
|
|
#include "nsPNGDecoder.h"
|
|
|
|
#include "nsGIFDecoder2.h"
|
|
|
|
#include "nsJPEGDecoder.h"
|
|
|
|
#include "nsBMPDecoder.h"
|
|
|
|
#include "nsICODecoder.h"
|
|
|
|
#include "nsIconDecoder.h"
|
2013-03-19 23:03:07 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "gfxContext.h"
|
|
|
|
|
2014-04-15 11:02:23 -07:00
|
|
|
#include "mozilla/gfx/2D.h"
|
|
|
|
#include "mozilla/RefPtr.h"
|
2014-09-12 01:12:55 -07:00
|
|
|
#include "mozilla/Move.h"
|
2013-06-23 05:03:39 -07:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2013-03-01 15:17:24 -08:00
|
|
|
#include "mozilla/Services.h"
|
2013-07-30 07:25:31 -07:00
|
|
|
#include <stdint.h>
|
2012-01-11 00:23:07 -08:00
|
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
#include "mozilla/TimeStamp.h"
|
2012-02-09 12:04:30 -08:00
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2012-04-03 14:57:22 -07:00
|
|
|
#include "mozilla/gfx/Scale.h"
|
|
|
|
|
2013-03-18 07:25:50 -07:00
|
|
|
#include "GeckoProfiler.h"
|
2013-09-07 06:01:08 -07:00
|
|
|
#include "gfx2DGlue.h"
|
2014-09-22 14:30:20 -07:00
|
|
|
#include "gfxPrefs.h"
|
2013-01-15 04:22:03 -08:00
|
|
|
#include <algorithm>
|
2012-10-03 13:36:26 -07:00
|
|
|
|
2013-06-03 03:14:42 -07:00
|
|
|
#ifdef MOZ_NUWA_PROCESS
|
|
|
|
#include "ipc/Nuwa.h"
|
|
|
|
#endif
|
|
|
|
|
2014-07-10 08:00:31 -07:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace gfx;
|
|
|
|
using namespace layers;
|
|
|
|
|
|
|
|
namespace image {
|
2014-10-15 13:52:20 -07:00
|
|
|
|
2014-07-28 14:27:39 -07:00
|
|
|
using std::ceil;
|
2014-10-15 13:52:20 -07:00
|
|
|
using std::min;
|
2010-08-13 21:09:49 -07:00
|
|
|
|
2011-01-12 17:45:13 -08:00
|
|
|
// a mask for flags that will affect the decoding
|
|
|
|
#define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
|
|
|
|
#define DECODE_FLAGS_DEFAULT 0
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
static uint32_t
|
|
|
|
DecodeFlags(uint32_t aFlags)
|
|
|
|
{
|
|
|
|
return aFlags & DECODE_FLAGS_MASK;
|
|
|
|
}
|
|
|
|
|
2007-10-18 17:36:34 -07:00
|
|
|
/* Accounting for compressed data */
|
|
|
|
#if defined(PR_LOGGING)
|
2012-10-29 16:32:10 -07:00
|
|
|
static PRLogModuleInfo *
|
|
|
|
GetCompressedImageAccountingLog()
|
|
|
|
{
|
|
|
|
static PRLogModuleInfo *sLog;
|
|
|
|
if (!sLog)
|
|
|
|
sLog = PR_NewLogModule("CompressedImageAccounting");
|
|
|
|
return sLog;
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
#else
|
2012-10-29 16:32:10 -07:00
|
|
|
#define GetCompressedImageAccountingLog()
|
2007-10-18 17:36:34 -07:00
|
|
|
#endif
|
|
|
|
|
2013-01-03 13:06:08 -08:00
|
|
|
// The maximum number of times any one RasterImage was decoded. This is only
|
|
|
|
// used for statistics.
|
|
|
|
static int32_t sMaxDecodeCount = 0;
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
/* We define our own error checking macros here for 2 reasons:
|
|
|
|
*
|
|
|
|
* 1) Most of the failures we encounter here will (hopefully) be
|
|
|
|
* the result of decoding failures (ie, bad data) and not code
|
|
|
|
* failures. As such, we don't want to clutter up debug consoles
|
|
|
|
* with spurious messages about NS_ENSURE_SUCCESS failures.
|
|
|
|
*
|
|
|
|
* 2) We want to set the internal error flag, shutdown properly,
|
|
|
|
* and end up in an error state.
|
|
|
|
*
|
|
|
|
* So this macro should be called when the desired failure behavior
|
|
|
|
* is to put the container into an error state and return failure.
|
|
|
|
* It goes without saying that macro won't compile outside of a
|
2010-08-13 21:09:49 -07:00
|
|
|
* non-static RasterImage method.
|
2009-09-12 15:44:18 -07:00
|
|
|
*/
|
|
|
|
#define LOG_CONTAINER_ERROR \
|
|
|
|
PR_BEGIN_MACRO \
|
2012-10-29 16:32:10 -07:00
|
|
|
PR_LOG (GetImgLog(), PR_LOG_ERROR, \
|
2010-08-13 21:09:49 -07:00
|
|
|
("RasterImage: [this=%p] Error " \
|
2009-09-12 15:44:18 -07:00
|
|
|
"detected at line %u for image of " \
|
|
|
|
"type %s\n", this, __LINE__, \
|
|
|
|
mSourceDataMimeType.get())); \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
|
|
|
#define CONTAINER_ENSURE_SUCCESS(status) \
|
|
|
|
PR_BEGIN_MACRO \
|
|
|
|
nsresult _status = status; /* eval once */ \
|
2012-08-14 02:10:41 -07:00
|
|
|
if (NS_FAILED(_status)) { \
|
2009-09-12 15:44:18 -07:00
|
|
|
LOG_CONTAINER_ERROR; \
|
|
|
|
DoError(); \
|
|
|
|
return _status; \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
|
|
|
#define CONTAINER_ENSURE_TRUE(arg, rv) \
|
|
|
|
PR_BEGIN_MACRO \
|
|
|
|
if (!(arg)) { \
|
|
|
|
LOG_CONTAINER_ERROR; \
|
|
|
|
DoError(); \
|
|
|
|
return rv; \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int num_containers;
|
|
|
|
static int num_discardable_containers;
|
2012-08-22 08:56:38 -07:00
|
|
|
static int64_t total_source_bytes;
|
|
|
|
static int64_t discardable_source_bytes;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
/* Are we globally disabling image discarding? */
|
2011-07-20 14:52:30 -07:00
|
|
|
static bool
|
2009-09-12 15:44:18 -07:00
|
|
|
DiscardingEnabled()
|
|
|
|
{
|
2011-07-20 14:52:30 -07:00
|
|
|
static bool inited;
|
|
|
|
static bool enabled;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (!inited) {
|
2011-10-17 07:59:28 -07:00
|
|
|
inited = true;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nullptr);
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
class ScaleRunner : public nsRunnable
|
2012-10-12 15:24:47 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
enum ScaleState
|
|
|
|
{
|
|
|
|
eNew,
|
|
|
|
eReady,
|
|
|
|
eFinish,
|
|
|
|
eFinishWithError
|
|
|
|
};
|
|
|
|
|
2013-01-04 19:55:23 -08:00
|
|
|
public:
|
2014-09-19 14:53:29 -07:00
|
|
|
ScaleRunner(RasterImage* aImage,
|
|
|
|
uint32_t aImageFlags,
|
|
|
|
const nsIntSize& aSize,
|
|
|
|
RawAccessFrameRef&& aSrcRef)
|
|
|
|
: mImage(aImage)
|
|
|
|
, mSrcRef(Move(aSrcRef))
|
|
|
|
, mDstSize(aSize)
|
|
|
|
, mImageFlags(aImageFlags)
|
|
|
|
, mState(eNew)
|
2012-10-12 15:24:47 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
MOZ_ASSERT(!mSrcRef->GetIsPaletted());
|
2014-08-22 13:12:38 -07:00
|
|
|
MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
|
2012-10-12 15:24:47 -07:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
bool Init()
|
2012-10-12 15:24:47 -07:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2014-09-19 14:53:29 -07:00
|
|
|
MOZ_ASSERT(mState == eNew, "Calling Init() twice?");
|
2012-10-12 15:24:47 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// We'll need a destination frame. It's unconditionally ARGB32 because
|
|
|
|
// that's what the scaler outputs.
|
|
|
|
nsRefPtr<imgFrame> tentativeDstFrame = new imgFrame();
|
|
|
|
nsresult rv =
|
|
|
|
tentativeDstFrame->InitForDecoder(mDstSize, SurfaceFormat::B8G8R8A8);
|
|
|
|
if (NS_FAILED(rv)) {
|
2012-10-12 15:24:47 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// We need a strong reference to the raw data for the destination frame.
|
|
|
|
// (We already got one for the source frame in the constructor.)
|
|
|
|
RawAccessFrameRef tentativeDstRef = tentativeDstFrame->RawAccessRef();
|
|
|
|
if (!tentativeDstRef) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-12 01:12:55 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// Everything worked, so commit to these objects and mark ourselves ready.
|
|
|
|
mDstRef = Move(tentativeDstRef);
|
|
|
|
mState = eReady;
|
2014-09-16 22:30:11 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// Insert the new surface into the cache immediately. We need to do this so
|
|
|
|
// that we won't start multiple scaling jobs for the same size.
|
|
|
|
SurfaceCache::Insert(mDstRef.get(), ImageKey(mImage.get()),
|
|
|
|
RasterSurfaceKey(mDstSize.ToIntSize(), mImageFlags));
|
2012-10-12 15:24:47 -07:00
|
|
|
|
2014-09-12 01:12:55 -07:00
|
|
|
return true;
|
2012-10-12 15:24:47 -07:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
NS_IMETHOD Run() MOZ_OVERRIDE
|
2012-10-12 15:24:47 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
if (mState == eReady) {
|
|
|
|
// Collect information from the frames that we need to scale.
|
|
|
|
uint8_t* srcData = mSrcRef->GetImageData();
|
|
|
|
IntSize srcSize = mSrcRef->GetSize();
|
|
|
|
uint32_t srcStride = mSrcRef->GetImageBytesPerRow();
|
|
|
|
uint8_t* dstData = mDstRef->GetImageData();
|
|
|
|
uint32_t dstStride = mDstRef->GetImageBytesPerRow();
|
|
|
|
SurfaceFormat srcFormat = mSrcRef->GetFormat();
|
2014-09-16 22:30:11 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// Actually do the scaling.
|
|
|
|
bool succeeded =
|
|
|
|
gfx::Scale(srcData, srcSize.width, srcSize.height, srcStride,
|
|
|
|
dstData, mDstSize.width, mDstSize.height, dstStride,
|
|
|
|
srcFormat);
|
2014-09-16 22:30:11 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
if (succeeded) {
|
|
|
|
// Mark the frame as complete and discardable.
|
|
|
|
mDstRef->ImageUpdated(mDstRef->GetRect());
|
|
|
|
MOZ_ASSERT(mDstRef->ImageComplete(),
|
|
|
|
"Incomplete, but just updated the entire frame");
|
|
|
|
if (DiscardingEnabled()) {
|
|
|
|
mDstRef->SetDiscardable();
|
|
|
|
}
|
|
|
|
}
|
2014-09-16 22:30:11 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// We need to send notifications and release our references on the main
|
|
|
|
// thread, so finish up there.
|
|
|
|
mState = succeeded ? eFinish : eFinishWithError;
|
|
|
|
NS_DispatchToMainThread(this);
|
|
|
|
} else if (mState == eFinish) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mDstRef, "Should have a valid scaled frame");
|
|
|
|
|
|
|
|
// Notify, so observers can redraw.
|
|
|
|
nsRefPtr<RasterImage> image = mImage.get();
|
|
|
|
if (image) {
|
|
|
|
image->NotifyNewScaledFrame();
|
2012-10-12 15:24:47 -07:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// We're done, so release everything.
|
|
|
|
mSrcRef.reset();
|
|
|
|
mDstRef.reset();
|
|
|
|
} else if (mState == eFinishWithError) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
NS_WARNING("HQ scaling failed");
|
|
|
|
|
|
|
|
// Remove the frame from the cache since we know we don't need it.
|
|
|
|
SurfaceCache::RemoveIfPresent(ImageKey(mImage.get()),
|
|
|
|
RasterSurfaceKey(mDstSize.ToIntSize(),
|
|
|
|
mImageFlags));
|
|
|
|
|
|
|
|
// Release everything we're holding, too.
|
|
|
|
mSrcRef.reset();
|
|
|
|
mDstRef.reset();
|
|
|
|
} else {
|
|
|
|
// mState must be eNew, which is invalid in Run().
|
|
|
|
MOZ_ASSERT(false, "Need to call Init() before dispatching");
|
2014-09-14 23:17:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
private:
|
|
|
|
virtual ~ScaleRunner()
|
2014-09-16 22:30:11 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
MOZ_ASSERT(!mSrcRef && !mDstRef,
|
|
|
|
"Should have released strong refs in Run()");
|
2012-10-12 15:24:47 -07:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
WeakPtr<RasterImage> mImage;
|
|
|
|
RawAccessFrameRef mSrcRef;
|
|
|
|
RawAccessFrameRef mDstRef;
|
|
|
|
const nsIntSize mDstSize;
|
|
|
|
uint32_t mImageFlags;
|
|
|
|
ScaleState mState;
|
2012-10-12 15:24:47 -07:00
|
|
|
};
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
/* static */ StaticRefPtr<RasterImage::DecodePool> RasterImage::DecodePool::sSingleton;
|
2012-04-03 14:57:22 -07:00
|
|
|
static nsCOMPtr<nsIThread> sScaleWorkerThread = nullptr;
|
|
|
|
|
2010-09-07 17:34:18 -07:00
|
|
|
#ifndef DEBUG
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties)
|
2010-09-07 17:34:18 -07:00
|
|
|
#else
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties,
|
|
|
|
imgIContainerDebug)
|
2010-09-07 17:34:18 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
//******************************************************************************
|
2014-11-14 20:10:47 -08:00
|
|
|
RasterImage::RasterImage(ProgressTracker* aProgressTracker,
|
2013-09-28 11:28:42 -07:00
|
|
|
ImageURL* aURI /* = nullptr */) :
|
2013-09-28 11:28:44 -07:00
|
|
|
ImageResource(aURI), // invoke superclass's constructor
|
2007-03-22 10:30:00 -07:00
|
|
|
mSize(0,0),
|
2011-01-12 17:45:13 -08:00
|
|
|
mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
|
2010-05-12 14:41:47 -07:00
|
|
|
mLockCount(0),
|
2011-09-08 11:05:11 -07:00
|
|
|
mDecodeCount(0),
|
2014-02-28 13:43:14 -08:00
|
|
|
mRequestedSampleSize(0),
|
2010-09-07 17:34:18 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
mFramesNotified(0),
|
|
|
|
#endif
|
2013-12-17 14:04:31 -08:00
|
|
|
mDecodingMonitor("RasterImage Decoding Monitor"),
|
2013-03-01 15:17:24 -08:00
|
|
|
mDecoder(nullptr),
|
2014-11-14 20:10:47 -08:00
|
|
|
mNotifyProgress(NoProgress),
|
2013-11-26 17:22:44 -08:00
|
|
|
mNotifying(false),
|
2011-10-17 07:59:28 -07:00
|
|
|
mHasSize(false),
|
|
|
|
mDecodeOnDraw(false),
|
|
|
|
mMultipart(false),
|
|
|
|
mDiscardable(false),
|
|
|
|
mHasSourceData(false),
|
|
|
|
mDecoded(false),
|
|
|
|
mHasBeenDecoded(false),
|
2012-09-17 18:53:37 -07:00
|
|
|
mAnimationFinished(false),
|
2013-01-31 10:38:24 -08:00
|
|
|
mWantFullDecode(false),
|
2014-09-19 14:53:29 -07:00
|
|
|
mPendingError(false)
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
2014-11-14 20:10:47 -08:00
|
|
|
mProgressTrackerInit = new ProgressTrackerInit(this, aProgressTracker);
|
2013-09-28 11:28:44 -07:00
|
|
|
|
2010-07-01 10:39:44 -07:00
|
|
|
// Set up the discard tracker node.
|
2012-03-15 13:30:41 -07:00
|
|
|
mDiscardTrackerNode.img = this;
|
2011-09-08 11:05:11 -07:00
|
|
|
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
|
2010-07-01 10:39:44 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Statistics
|
|
|
|
num_containers++;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::~RasterImage()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
// Discardable statistics
|
|
|
|
if (mDiscardable) {
|
|
|
|
num_discardable_containers--;
|
|
|
|
discardable_source_bytes -= mSourceData.Length();
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2012-10-29 16:32:10 -07:00
|
|
|
PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
2010-08-13 21:09:49 -07:00
|
|
|
("CompressedImageAccounting: destroying RasterImage %p. "
|
2009-09-12 15:44:18 -07:00
|
|
|
"Total Containers: %d, Discardable containers: %d, "
|
|
|
|
"Total source bytes: %lld, Source bytes for discardable containers %lld",
|
2007-10-18 17:36:34 -07:00
|
|
|
this,
|
2009-09-12 15:44:18 -07:00
|
|
|
num_containers,
|
|
|
|
num_discardable_containers,
|
|
|
|
total_source_bytes,
|
|
|
|
discardable_source_bytes));
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mDecoder) {
|
2012-10-22 10:16:57 -07:00
|
|
|
// Kill off our decode request, if it's pending. (If not, this call is
|
|
|
|
// harmless.)
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodePool::StopDecoding(this);
|
2012-10-22 10:16:57 -07:00
|
|
|
mDecoder = nullptr;
|
2013-02-27 11:23:08 -08:00
|
|
|
|
|
|
|
// Unlock the last frame (if we have any). Our invariant is that, while we
|
|
|
|
// have a decoder open, the last frame is always locked.
|
|
|
|
// This would be done in ShutdownDecoder, but since mDecoder is non-null,
|
|
|
|
// we didn't call ShutdownDecoder and we need to do it manually.
|
2013-06-17 13:49:04 -07:00
|
|
|
if (GetNumFrames() > 0) {
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
|
2013-02-27 11:23:08 -08:00
|
|
|
curframe->UnlockImageData();
|
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// Release any HQ scaled frames from the surface cache.
|
|
|
|
SurfaceCache::Discard(this);
|
|
|
|
|
2013-09-28 11:28:44 -07:00
|
|
|
mAnim = nullptr;
|
2013-04-03 19:19:38 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Total statistics
|
|
|
|
num_containers--;
|
|
|
|
total_source_bytes -= mSourceData.Length();
|
2012-11-07 11:03:10 -08:00
|
|
|
|
2012-11-07 14:25:27 -08:00
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
DiscardTracker::Remove(&mDiscardTrackerNode);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-02-13 14:03:37 -08:00
|
|
|
/* static */ void
|
2012-09-26 08:33:06 -07:00
|
|
|
RasterImage::Initialize()
|
|
|
|
{
|
|
|
|
// Create our singletons now, so we don't have to worry about what thread
|
|
|
|
// they're created on.
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodePool::Singleton();
|
2012-09-26 08:33:06 -07:00
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2013-02-12 19:00:03 -08:00
|
|
|
RasterImage::Init(const char* aMimeType,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aFlags)
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
|
|
|
// We don't support re-initialization
|
|
|
|
if (mInitialized)
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
|
|
|
// Not sure an error can happen before init, but be safe
|
|
|
|
if (mError)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aMimeType);
|
|
|
|
|
|
|
|
// We must be non-discardable and non-decode-on-draw for
|
|
|
|
// multipart channels
|
|
|
|
NS_ABORT_IF_FALSE(!(aFlags & INIT_FLAG_MULTIPART) ||
|
|
|
|
(!(aFlags & INIT_FLAG_DISCARDABLE) &&
|
|
|
|
!(aFlags & INIT_FLAG_DECODE_ON_DRAW)),
|
|
|
|
"Can't be discardable or decode-on-draw for multipart");
|
2008-01-19 00:10:26 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Store initialization data
|
|
|
|
mSourceDataMimeType.Assign(aMimeType);
|
2010-05-25 15:27:29 -07:00
|
|
|
mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
|
|
|
|
mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
|
|
|
|
mMultipart = !!(aFlags & INIT_FLAG_MULTIPART);
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
// Statistics
|
|
|
|
if (mDiscardable) {
|
|
|
|
num_discardable_containers++;
|
|
|
|
discardable_source_bytes += mSourceData.Length();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instantiate the decoder
|
2013-02-01 11:36:39 -08:00
|
|
|
nsresult rv = InitDecoder(/* aDoSizeDecode = */ true);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
|
2013-02-01 11:36:39 -08:00
|
|
|
// If we aren't storing source data, we want to switch from a size decode to
|
|
|
|
// a full decode as soon as possible.
|
|
|
|
if (!StoringSourceData()) {
|
|
|
|
mWantFullDecode = true;
|
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Mark us as initialized
|
2011-10-17 07:59:28 -07:00
|
|
|
mInitialized = true;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-11-09 13:39:15 -08:00
|
|
|
//******************************************************************************
|
2011-11-09 13:39:16 -08:00
|
|
|
// [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
|
2011-11-09 13:39:15 -08:00
|
|
|
NS_IMETHODIMP_(void)
|
2014-06-16 15:25:43 -07:00
|
|
|
RasterImage::RequestRefresh(const TimeStamp& aTime)
|
2011-11-09 13:39:15 -08:00
|
|
|
{
|
2014-05-08 11:37:39 -07:00
|
|
|
if (HadRecentRefresh(aTime)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-03 13:20:15 -07:00
|
|
|
EvaluateAnimation();
|
|
|
|
|
|
|
|
if (!mAnimating) {
|
2011-11-09 13:39:16 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
FrameAnimator::RefreshResult res;
|
|
|
|
if (mAnim) {
|
|
|
|
res = mAnim->RequestRefresh(aTime);
|
2011-11-09 13:39:16 -08:00
|
|
|
}
|
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
if (res.frameAdvanced) {
|
2011-11-09 13:39:16 -08:00
|
|
|
// Notify listeners that our frame has actually changed, but do this only
|
|
|
|
// once for all frames that we've now passed (if AdvanceFrame() was called
|
|
|
|
// more than once).
|
|
|
|
#ifdef DEBUG
|
|
|
|
mFramesNotified++;
|
|
|
|
#endif
|
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
UpdateImageContainer();
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2014-11-14 20:10:47 -08:00
|
|
|
if (mProgressTracker) {
|
|
|
|
mProgressTracker->SyncNotifyProgress(NoProgress, res.dirtyRect);
|
2014-11-10 12:37:35 -08:00
|
|
|
}
|
2013-07-15 11:38:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (res.animationFinished) {
|
|
|
|
mAnimationFinished = true;
|
|
|
|
EvaluateAnimation();
|
2011-11-09 13:39:16 -08:00
|
|
|
}
|
2011-11-09 13:39:15 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* readonly attribute int32_t width; */
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::GetWidth(int32_t *aWidth)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-03-19 22:54:30 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aWidth);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-06 15:18:52 -07:00
|
|
|
if (mError) {
|
|
|
|
*aWidth = 0;
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2010-10-06 15:18:52 -07:00
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
*aWidth = mSize.width;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* readonly attribute int32_t height; */
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::GetHeight(int32_t *aHeight)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-03-19 22:54:30 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aHeight);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-06 15:18:52 -07:00
|
|
|
if (mError) {
|
|
|
|
*aHeight = 0;
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2010-10-06 15:18:52 -07:00
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
*aHeight = mSize.height;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2013-01-10 19:38:34 -08:00
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] readonly attribute nsSize intrinsicSize; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::GetIntrinsicSize(nsSize* aSize)
|
|
|
|
{
|
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
*aSize = nsSize(nsPresContext::CSSPixelsToAppUnits(mSize.width),
|
|
|
|
nsPresContext::CSSPixelsToAppUnits(mSize.height));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] readonly attribute nsSize intrinsicRatio; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::GetIntrinsicRatio(nsSize* aRatio)
|
|
|
|
{
|
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
*aRatio = nsSize(mSize.width, mSize.height);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-08-25 00:19:42 -07:00
|
|
|
NS_IMETHODIMP_(Orientation)
|
|
|
|
RasterImage::GetOrientation()
|
|
|
|
{
|
|
|
|
return mOrientation;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* unsigned short GetType(); */
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::GetType(uint16_t *aType)
|
2010-08-13 21:09:49 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aType);
|
|
|
|
|
2010-12-07 10:40:28 -08:00
|
|
|
*aType = GetType();
|
2010-08-13 21:09:49 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-12-07 10:40:28 -08:00
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* [noscript, notxpcom] uint16_t GetType(); */
|
|
|
|
NS_IMETHODIMP_(uint16_t)
|
2010-12-07 10:40:28 -08:00
|
|
|
RasterImage::GetType()
|
|
|
|
{
|
|
|
|
return imgIContainer::TYPE_RASTER;
|
|
|
|
}
|
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
already_AddRefed<imgFrame>
|
2014-09-26 18:50:24 -07:00
|
|
|
RasterImage::LookupFrameNoDecode(uint32_t aFrameNum)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
if (!mAnim) {
|
2014-09-12 18:29:27 -07:00
|
|
|
NS_ASSERTION(aFrameNum == 0, "Don't ask for a frame > 0 if we're not animated!");
|
2013-06-17 13:49:04 -07:00
|
|
|
return mFrameBlender.GetFrame(0);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
2014-09-12 18:29:27 -07:00
|
|
|
return mFrameBlender.GetFrame(aFrameNum);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
DrawableFrameRef
|
2014-09-26 18:50:24 -07:00
|
|
|
RasterImage::LookupFrame(uint32_t aFrameNum,
|
|
|
|
uint32_t aFlags,
|
|
|
|
bool aShouldSyncNotify /* = true */)
|
2011-07-21 11:14:41 -07:00
|
|
|
{
|
2014-09-12 18:29:27 -07:00
|
|
|
if (mMultipart &&
|
|
|
|
aFrameNum == GetCurrentFrameIndex() &&
|
|
|
|
mMultipartDecodedFrame) {
|
2013-04-04 15:05:19 -07:00
|
|
|
// In the multipart case we prefer to use mMultipartDecodedFrame, which is
|
|
|
|
// the most recent one we completely decoded, rather than display the real
|
|
|
|
// current frame and risk severe tearing.
|
2014-09-12 18:29:27 -07:00
|
|
|
return mMultipartDecodedFrame->DrawableRef();
|
2013-04-04 15:46:08 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
// Try our best to start decoding if it's necessary.
|
2014-09-26 18:50:24 -07:00
|
|
|
nsresult rv = WantDecodedFrames(aFlags, aShouldSyncNotify);
|
2014-09-12 18:29:27 -07:00
|
|
|
CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), DrawableFrameRef());
|
|
|
|
|
2014-09-26 18:50:24 -07:00
|
|
|
nsRefPtr<imgFrame> frame = LookupFrameNoDecode(aFrameNum);
|
2013-04-04 15:46:08 -07:00
|
|
|
if (!frame) {
|
2014-09-12 18:29:27 -07:00
|
|
|
return DrawableFrameRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
DrawableFrameRef ref = frame->DrawableRef();
|
|
|
|
if (!ref) {
|
|
|
|
// The OS threw this frame away. We need to discard and redecode.
|
|
|
|
MOZ_ASSERT(!mAnim, "Animated frames should be locked");
|
2014-09-24 14:26:13 -07:00
|
|
|
if (CanForciblyDiscardAndRedecode()) {
|
|
|
|
ForceDiscard();
|
2014-09-26 18:50:24 -07:00
|
|
|
WantDecodedFrames(aFlags, aShouldSyncNotify);
|
|
|
|
|
|
|
|
// See if we managed to entirely redecode the frame.
|
|
|
|
frame = LookupFrameNoDecode(aFrameNum);
|
|
|
|
ref = frame->DrawableRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ref) {
|
|
|
|
// We didn't successfully redecode, so just fail.
|
|
|
|
return DrawableFrameRef();
|
2014-09-24 14:26:13 -07:00
|
|
|
}
|
2013-04-04 15:05:19 -07:00
|
|
|
}
|
2009-11-12 15:18:40 -08:00
|
|
|
|
|
|
|
// We will return a paletted frame if it's not marked as compositing failed
|
|
|
|
// so we can catch crashes for reasons we haven't investigated.
|
2014-09-12 18:29:27 -07:00
|
|
|
if (ref->GetCompositingFailed()) {
|
|
|
|
return DrawableFrameRef();
|
|
|
|
}
|
2013-07-26 07:41:57 -07:00
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
return ref;
|
2009-11-12 15:18:40 -08:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t
|
2014-09-12 18:29:27 -07:00
|
|
|
RasterImage::GetCurrentFrameIndex() const
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2014-09-12 18:29:27 -07:00
|
|
|
if (mAnim) {
|
2013-07-15 11:38:59 -07:00
|
|
|
return mAnim->GetCurrentAnimationFrameIndex();
|
2014-09-12 18:29:27 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
uint32_t
|
|
|
|
RasterImage::GetRequestedFrameIndex(uint32_t aWhichFrame) const
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2014-09-12 18:29:27 -07:00
|
|
|
return aWhichFrame == FRAME_FIRST ? 0 : GetCurrentFrameIndex();
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2014-11-10 12:37:35 -08:00
|
|
|
nsIntRect
|
|
|
|
RasterImage::GetFirstFrameRect()
|
|
|
|
{
|
|
|
|
if (mAnim) {
|
|
|
|
return mAnim->GetFirstFrameRefreshArea();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to our size. This is implicitly zero-size if !mHasSize.
|
|
|
|
return nsIntRect(nsIntPoint(0,0), mSize);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//******************************************************************************
|
2013-02-04 14:22:30 -08:00
|
|
|
/* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */
|
|
|
|
NS_IMETHODIMP_(bool)
|
|
|
|
RasterImage::FrameIsOpaque(uint32_t aWhichFrame)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-02-04 14:22:30 -08:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE) {
|
|
|
|
NS_WARNING("aWhichFrame outside valid range!");
|
|
|
|
return false;
|
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
2013-02-04 14:22:30 -08:00
|
|
|
return false;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-02-04 14:22:30 -08:00
|
|
|
// See if we can get an image frame.
|
2014-09-12 18:29:27 -07:00
|
|
|
nsRefPtr<imgFrame> frame =
|
2014-09-26 18:50:24 -07:00
|
|
|
LookupFrameNoDecode(GetRequestedFrameIndex(aWhichFrame));
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2013-02-04 14:22:30 -08:00
|
|
|
// If we don't get a frame, the safe answer is "not opaque".
|
|
|
|
if (!frame)
|
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-02-04 14:22:30 -08:00
|
|
|
// Other, the frame is transparent if either:
|
|
|
|
// 1. It needs a background.
|
|
|
|
// 2. Its size doesn't cover our entire area.
|
|
|
|
nsIntRect framerect = frame->GetRect();
|
|
|
|
return !frame->GetNeedsBackground() &&
|
|
|
|
framerect.IsEqualInterior(nsIntRect(0, 0, mSize.width, mSize.height));
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2013-02-04 16:06:14 -08:00
|
|
|
nsIntRect
|
|
|
|
RasterImage::FrameRect(uint32_t aWhichFrame)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2013-02-04 16:06:14 -08:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE) {
|
|
|
|
NS_WARNING("aWhichFrame outside valid range!");
|
|
|
|
return nsIntRect();
|
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2013-02-04 16:06:14 -08:00
|
|
|
// Get the requested frame.
|
2014-09-12 18:29:27 -07:00
|
|
|
nsRefPtr<imgFrame> frame =
|
2014-09-26 18:50:24 -07:00
|
|
|
LookupFrameNoDecode(GetRequestedFrameIndex(aWhichFrame));
|
2013-03-18 14:10:28 -07:00
|
|
|
|
2013-02-04 16:06:14 -08:00
|
|
|
// If we have the frame, use that rectangle.
|
|
|
|
if (frame) {
|
|
|
|
return frame->GetRect();
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
2013-02-04 16:06:14 -08:00
|
|
|
|
|
|
|
// If the frame doesn't exist, we return the empty rectangle. It's not clear
|
|
|
|
// whether this is appropriate in general, but at the moment the only
|
2014-11-14 20:10:47 -08:00
|
|
|
// consumer of this method is ProgressTracker (when it wants to figure out
|
2013-02-04 16:06:14 -08:00
|
|
|
// dirty rectangles to send out batched observer updates). This should
|
|
|
|
// probably be revisited when we fix bug 503973.
|
|
|
|
return nsIntRect();
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t
|
2013-06-17 13:49:04 -07:00
|
|
|
RasterImage::GetNumFrames() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-06-17 13:49:04 -07:00
|
|
|
return mFrameBlender.GetNumFrames();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
/* readonly attribute boolean animated; */
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
RasterImage::GetAnimated(bool *aAnimated)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aAnimated);
|
|
|
|
|
2009-10-06 21:39:30 -07:00
|
|
|
// If we have mAnim, we can know for sure
|
|
|
|
if (mAnim) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aAnimated = true;
|
2009-10-06 21:39:30 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we need to have been decoded to know for sure, since if we were
|
|
|
|
// decoded at least once mAnim would have been created for animated images
|
|
|
|
if (!mHasBeenDecoded)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
|
|
|
// We know for sure
|
2011-10-17 07:59:28 -07:00
|
|
|
*aAnimated = false;
|
2009-10-06 21:39:30 -07:00
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-17 10:42:20 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* [notxpcom] int32_t getFirstFrameDelay (); */
|
|
|
|
NS_IMETHODIMP_(int32_t)
|
|
|
|
RasterImage::GetFirstFrameDelay()
|
|
|
|
{
|
|
|
|
if (mError)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
bool animated = false;
|
|
|
|
if (NS_FAILED(GetAnimated(&animated)) || !animated)
|
|
|
|
return -1;
|
|
|
|
|
2013-12-06 01:45:24 -08:00
|
|
|
return mFrameBlender.GetTimeoutForFrame(0);
|
2013-05-17 10:42:20 -07:00
|
|
|
}
|
|
|
|
|
2014-04-19 18:28:38 -07:00
|
|
|
TemporaryRef<SourceSurface>
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::CopyFrame(uint32_t aWhichFrame,
|
2014-09-26 18:50:24 -07:00
|
|
|
uint32_t aFlags,
|
|
|
|
bool aShouldSyncNotify /* = true */)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE)
|
2014-04-19 18:28:38 -07:00
|
|
|
return nullptr;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
if (mError)
|
2014-04-19 18:28:38 -07:00
|
|
|
return nullptr;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2014-03-04 20:48:48 -08:00
|
|
|
if (!ApplyDecodeFlags(aFlags, aWhichFrame))
|
2014-04-19 18:28:38 -07:00
|
|
|
return nullptr;
|
2011-01-12 17:45:13 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Get the frame. If it's not there, it's probably the caller's fault for
|
|
|
|
// not waiting for the data to be loaded from the network or not passing
|
|
|
|
// FLAG_SYNC_DECODE
|
2014-09-26 18:50:24 -07:00
|
|
|
DrawableFrameRef frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
|
|
|
|
aFlags, aShouldSyncNotify);
|
2014-09-12 18:29:27 -07:00
|
|
|
if (!frameRef) {
|
2014-09-26 18:50:24 -07:00
|
|
|
// The OS threw this frame away and we couldn't redecode it right now.
|
2014-04-19 18:28:38 -07:00
|
|
|
return nullptr;
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
|
|
|
// Create a 32-bit image surface of our size, but draw using the frame's
|
|
|
|
// rect, implicitly padding the frame out to the image's size.
|
2014-04-19 18:28:38 -07:00
|
|
|
|
|
|
|
IntSize size(mSize.width, mSize.height);
|
|
|
|
RefPtr<DataSourceSurface> surf =
|
2014-09-10 14:54:16 -07:00
|
|
|
Factory::CreateDataSourceSurface(size,
|
|
|
|
SurfaceFormat::B8G8R8A8,
|
|
|
|
/* aZero = */ true);
|
2014-08-27 08:57:43 -07:00
|
|
|
if (NS_WARN_IF(!surf)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-04-19 18:28:38 -07:00
|
|
|
|
|
|
|
DataSourceSurface::MappedSurface mapping;
|
|
|
|
DebugOnly<bool> success =
|
|
|
|
surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
|
|
|
|
NS_ASSERTION(success, "Failed to map surface");
|
|
|
|
RefPtr<DrawTarget> target =
|
|
|
|
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
|
|
|
mapping.mData,
|
|
|
|
size,
|
|
|
|
mapping.mStride,
|
|
|
|
SurfaceFormat::B8G8R8A8);
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
nsIntRect intFrameRect = frameRef->GetRect();
|
|
|
|
Rect rect(intFrameRect.x, intFrameRect.y,
|
|
|
|
intFrameRect.width, intFrameRect.height);
|
|
|
|
if (frameRef->IsSinglePixel()) {
|
|
|
|
target->FillRect(rect, ColorPattern(frameRef->SinglePixelColor()),
|
2014-04-19 18:28:38 -07:00
|
|
|
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
|
|
|
} else {
|
2014-09-12 18:29:27 -07:00
|
|
|
RefPtr<SourceSurface> srcSurf = frameRef->GetSurface();
|
|
|
|
Rect srcRect(0, 0, intFrameRect.width, intFrameRect.height);
|
|
|
|
target->DrawSurface(srcSurf, srcRect, rect);
|
2014-04-19 18:28:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
target->Flush();
|
|
|
|
surf->Unmap();
|
|
|
|
|
|
|
|
return surf;
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
//******************************************************************************
|
2014-04-15 11:02:23 -07:00
|
|
|
/* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
|
|
|
|
* in uint32_t aFlags); */
|
|
|
|
NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::GetFrame(uint32_t aWhichFrame,
|
2013-12-13 00:34:24 -08:00
|
|
|
uint32_t aFlags)
|
2014-09-26 18:50:24 -07:00
|
|
|
{
|
|
|
|
return GetFrameInternal(aWhichFrame, aFlags);
|
|
|
|
}
|
|
|
|
|
|
|
|
TemporaryRef<SourceSurface>
|
|
|
|
RasterImage::GetFrameInternal(uint32_t aWhichFrame,
|
|
|
|
uint32_t aFlags,
|
|
|
|
bool aShouldSyncNotify /* = true */)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2013-12-13 00:34:24 -08:00
|
|
|
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE)
|
2013-12-13 00:34:24 -08:00
|
|
|
return nullptr;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
if (mError)
|
2013-12-13 00:34:24 -08:00
|
|
|
return nullptr;
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2014-03-04 20:48:48 -08:00
|
|
|
if (!ApplyDecodeFlags(aFlags, aWhichFrame))
|
2013-12-13 00:34:24 -08:00
|
|
|
return nullptr;
|
2012-08-13 09:34:32 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Get the frame. If it's not there, it's probably the caller's fault for
|
|
|
|
// not waiting for the data to be loaded from the network or not passing
|
|
|
|
// FLAG_SYNC_DECODE
|
2014-09-26 18:50:24 -07:00
|
|
|
DrawableFrameRef frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
|
|
|
|
aFlags, aShouldSyncNotify);
|
2014-09-12 18:29:27 -07:00
|
|
|
if (!frameRef) {
|
2014-09-26 18:50:24 -07:00
|
|
|
// The OS threw this frame away and we couldn't redecode it.
|
2013-12-13 00:34:24 -08:00
|
|
|
return nullptr;
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
// If this frame covers the entire image, we can just reuse its existing
|
|
|
|
// surface.
|
2014-09-12 18:29:27 -07:00
|
|
|
RefPtr<SourceSurface> frameSurf;
|
|
|
|
nsIntRect frameRect = frameRef->GetRect();
|
|
|
|
if (frameRect.x == 0 && frameRect.y == 0 &&
|
|
|
|
frameRect.width == mSize.width &&
|
|
|
|
frameRect.height == mSize.height) {
|
|
|
|
frameSurf = frameRef->GetSurface();
|
2014-02-24 19:37:51 -08:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
// The image doesn't have a usable surface because it's been optimized away or
|
|
|
|
// because it's a partial update frame from an animation. Create one.
|
|
|
|
if (!frameSurf) {
|
2014-09-26 18:50:24 -07:00
|
|
|
frameSurf = CopyFrame(aWhichFrame, aFlags, aShouldSyncNotify);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
return frameSurf;
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
already_AddRefed<layers::Image>
|
|
|
|
RasterImage::GetCurrentImage()
|
2011-11-08 19:14:41 -08:00
|
|
|
{
|
2014-09-26 18:50:24 -07:00
|
|
|
RefPtr<SourceSurface> surface =
|
|
|
|
GetFrameInternal(FRAME_CURRENT, FLAG_NONE, /* aShouldSyncNotify = */ false);
|
2014-04-15 11:02:23 -07:00
|
|
|
if (!surface) {
|
2014-09-26 18:50:24 -07:00
|
|
|
// The OS threw out some or all of our buffer. We'll need to wait for the
|
|
|
|
// redecode (which was automatically triggered by GetFrame) to complete.
|
2014-02-24 19:37:51 -08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2012-11-16 10:04:29 -08:00
|
|
|
|
2012-10-01 21:01:25 -07:00
|
|
|
if (!mImageContainer) {
|
|
|
|
mImageContainer = LayerManager::CreateImageContainer();
|
|
|
|
}
|
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
CairoImage::Data cairoData;
|
2011-11-08 19:14:41 -08:00
|
|
|
GetWidth(&cairoData.mSize.width);
|
|
|
|
GetHeight(&cairoData.mSize.height);
|
2014-04-15 11:02:23 -07:00
|
|
|
cairoData.mSourceSurface = surface;
|
2011-11-08 19:14:41 -08:00
|
|
|
|
2014-01-30 14:58:51 -08:00
|
|
|
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
|
2011-11-08 19:14:41 -08:00
|
|
|
NS_ASSERTION(image, "Failed to create Image");
|
2013-03-29 13:14:19 -07:00
|
|
|
|
2011-11-08 19:14:41 -08:00
|
|
|
static_cast<CairoImage*>(image.get())->SetData(cairoData);
|
2012-09-24 13:31:30 -07:00
|
|
|
|
|
|
|
return image.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-11-27 18:34:45 -08:00
|
|
|
RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
|
2012-09-24 13:31:30 -07:00
|
|
|
{
|
2012-11-27 18:34:45 -08:00
|
|
|
int32_t maxTextureSize = aManager->GetMaxTextureSize();
|
|
|
|
if (mSize.width > maxTextureSize || mSize.height > maxTextureSize) {
|
|
|
|
*_retval = nullptr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-11-14 20:10:47 -08:00
|
|
|
if (IsUnlocked() && mProgressTracker) {
|
|
|
|
mProgressTracker->OnUnlockedDraw();
|
2013-04-26 12:58:17 -07:00
|
|
|
}
|
|
|
|
|
2014-02-24 19:37:51 -08:00
|
|
|
if (!mImageContainer) {
|
|
|
|
mImageContainer = mImageContainerCache;
|
|
|
|
}
|
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
if (mImageContainer) {
|
|
|
|
*_retval = mImageContainer;
|
|
|
|
NS_ADDREF(*_retval);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-11-16 10:04:29 -08:00
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
nsRefPtr<layers::Image> image = GetCurrentImage();
|
|
|
|
if (!image) {
|
2012-11-16 10:04:29 -08:00
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2012-09-24 13:31:30 -07:00
|
|
|
}
|
2012-07-26 11:11:22 -07:00
|
|
|
mImageContainer->SetCurrentImageInTransaction(image);
|
2011-11-08 19:14:41 -08:00
|
|
|
|
|
|
|
*_retval = mImageContainer;
|
2012-01-29 21:16:54 -08:00
|
|
|
NS_ADDREF(*_retval);
|
2014-02-24 19:37:51 -08:00
|
|
|
// We only need to be careful about holding on to the image when it is
|
|
|
|
// discardable by the OS.
|
|
|
|
if (CanForciblyDiscardAndRedecode()) {
|
2014-07-30 12:52:05 -07:00
|
|
|
mImageContainerCache = mImageContainer;
|
2014-02-24 19:37:51 -08:00
|
|
|
mImageContainer = nullptr;
|
|
|
|
}
|
|
|
|
|
2011-11-08 19:14:41 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
void
|
|
|
|
RasterImage::UpdateImageContainer()
|
|
|
|
{
|
2014-11-14 20:06:21 -08:00
|
|
|
if (!mImageContainer) {
|
2012-09-24 13:31:30 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<layers::Image> image = GetCurrentImage();
|
|
|
|
if (!image) {
|
|
|
|
return;
|
|
|
|
}
|
2014-11-14 20:06:21 -08:00
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
mImageContainer->SetCurrentImage(image);
|
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
2013-06-23 05:03:39 -07:00
|
|
|
RasterImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
|
2012-02-19 19:51:48 -08:00
|
|
|
{
|
2013-03-29 13:14:19 -07:00
|
|
|
// n == 0 is possible for two reasons.
|
2012-02-19 19:51:48 -08:00
|
|
|
// - This is a zero-length image.
|
|
|
|
// - We're on a platform where moz_malloc_size_of always returns 0.
|
|
|
|
// In either case the fallback works appropriately.
|
|
|
|
size_t n = mSourceData.SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
if (n == 0) {
|
|
|
|
n = mSourceData.Length();
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
2011-07-18 06:20:27 -07:00
|
|
|
|
2012-10-13 19:17:40 -07:00
|
|
|
size_t
|
2013-09-24 13:45:13 -07:00
|
|
|
RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
|
2013-06-23 05:03:39 -07:00
|
|
|
MallocSizeOf aMallocSizeOf) const
|
2010-05-21 21:10:14 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
return mFrameBlender.SizeOfDecodedWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
|
2011-07-18 06:20:27 -07:00
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
2013-06-23 05:03:39 -07:00
|
|
|
RasterImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
|
2011-07-18 06:20:27 -07:00
|
|
|
{
|
2014-01-23 10:26:40 -08:00
|
|
|
return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_HEAP,
|
2012-10-13 19:17:40 -07:00
|
|
|
aMallocSizeOf);
|
2011-07-18 06:20:27 -07:00
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
|
|
|
RasterImage::NonHeapSizeOfDecoded() const
|
2011-07-18 06:20:27 -07:00
|
|
|
{
|
2014-01-23 10:26:40 -08:00
|
|
|
return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_NONHEAP,
|
2013-08-23 12:51:00 -07:00
|
|
|
nullptr);
|
2011-07-18 06:20:27 -07:00
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
|
|
|
RasterImage::OutOfProcessSizeOfDecoded() const
|
2010-05-21 21:10:14 -07:00
|
|
|
{
|
2014-01-23 10:26:40 -08:00
|
|
|
return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::OUT_OF_PROCESS,
|
2013-08-23 12:51:00 -07:00
|
|
|
nullptr);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
void
|
|
|
|
RasterImage::EnsureAnimExists()
|
|
|
|
{
|
|
|
|
if (!mAnim) {
|
|
|
|
|
|
|
|
// Create the animation context
|
2014-09-09 06:39:00 -07:00
|
|
|
mAnim = MakeUnique<FrameAnimator>(mFrameBlender, mAnimationMode);
|
2013-07-15 11:38:59 -07:00
|
|
|
|
|
|
|
// We don't support discarding animated images (See bug 414259).
|
|
|
|
// Lock the image and throw away the key.
|
|
|
|
//
|
|
|
|
// Note that this is inefficient, since we could get rid of the source
|
|
|
|
// data too. However, doing this is actually hard, because we're probably
|
|
|
|
// calling ensureAnimExists mid-decode, and thus we're decoding out of
|
|
|
|
// the source buffer. Since we're going to fix this anyway later, and
|
|
|
|
// since we didn't kill the source data in the old world either, locking
|
|
|
|
// is acceptable for the moment.
|
|
|
|
LockImage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::InternalAddFrameHelper(uint32_t framenum, imgFrame *aFrame,
|
|
|
|
uint8_t **imageData, uint32_t *imageLength,
|
2013-02-27 11:23:08 -08:00
|
|
|
uint32_t **paletteData, uint32_t *paletteLength,
|
|
|
|
imgFrame** aRetFrame)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2013-06-17 13:49:04 -07:00
|
|
|
NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
|
|
|
|
if (framenum > GetNumFrames())
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> frame(aFrame);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// We are in the middle of decoding. This will be unlocked when we finish
|
|
|
|
// decoding or switch to another frame.
|
2012-09-26 08:33:06 -07:00
|
|
|
frame->LockImageData();
|
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
if (paletteData && paletteLength)
|
|
|
|
frame->GetPaletteData(paletteData, paletteLength);
|
|
|
|
|
|
|
|
frame->GetImageData(imageData, imageLength);
|
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
mFrameBlender.InsertFrame(framenum, frame);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
frame.forget(aRetFrame);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-02-27 11:23:08 -08:00
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::InternalAddFrame(uint32_t framenum,
|
|
|
|
int32_t aX, int32_t aY,
|
|
|
|
int32_t aWidth, int32_t aHeight,
|
2014-04-19 18:28:38 -07:00
|
|
|
SurfaceFormat aFormat,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint8_t aPaletteDepth,
|
|
|
|
uint8_t **imageData,
|
|
|
|
uint32_t *imageLength,
|
|
|
|
uint32_t **paletteData,
|
2013-02-27 11:23:08 -08:00
|
|
|
uint32_t *paletteLength,
|
|
|
|
imgFrame** aRetFrame)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2010-02-25 10:14:30 -08:00
|
|
|
// We assume that we're in the middle of decoding because we unlock the
|
|
|
|
// previous frame when we create a new frame, and only when decoding do we
|
|
|
|
// lock frames.
|
2013-02-27 11:23:08 -08:00
|
|
|
NS_ABORT_IF_FALSE(mDecoder, "Only decoders may add frames!");
|
2010-02-25 10:14:30 -08:00
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
|
|
|
|
if (framenum > GetNumFrames())
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> frame(new imgFrame());
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2014-09-14 15:22:45 -07:00
|
|
|
nsIntRect frameRect(aX, aY, aWidth, aHeight);
|
|
|
|
nsresult rv = frame->InitForDecoder(frameRect, aFormat, aPaletteDepth);
|
2013-05-22 02:10:38 -07:00
|
|
|
if (!(mSize.width > 0 && mSize.height > 0))
|
|
|
|
NS_WARNING("Shouldn't call InternalAddFrame with zero size");
|
|
|
|
if (!NS_SUCCEEDED(rv))
|
|
|
|
NS_WARNING("imgFrame::Init should succeed");
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2010-02-25 10:14:30 -08:00
|
|
|
// We know we are in a decoder. Therefore, we must unlock the previous frame
|
|
|
|
// when we move on to decoding into the next frame.
|
2013-06-17 13:49:04 -07:00
|
|
|
if (GetNumFrames() > 0) {
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> prevframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
|
2010-02-25 10:14:30 -08:00
|
|
|
prevframe->UnlockImageData();
|
|
|
|
}
|
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
if (GetNumFrames() == 0) {
|
2014-08-22 13:49:54 -07:00
|
|
|
return InternalAddFrameHelper(framenum, frame, imageData, imageLength,
|
2013-02-27 11:23:08 -08:00
|
|
|
paletteData, paletteLength, aRetFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
if (GetNumFrames() == 1) {
|
2007-10-22 09:13:37 -07:00
|
|
|
// Since we're about to add our second frame, initialize animation stuff
|
2011-07-23 11:49:00 -07:00
|
|
|
EnsureAnimExists();
|
2013-03-29 13:14:19 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If we dispose of the first frame by clearing it, then the
|
|
|
|
// First Frame's refresh area is all of itself.
|
|
|
|
// RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR)
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> firstFrame = mFrameBlender.RawGetFrame(0);
|
|
|
|
int32_t frameDisposalMethod = firstFrame->GetFrameDisposalMethod();
|
2013-06-17 13:49:04 -07:00
|
|
|
if (frameDisposalMethod == FrameBlender::kDisposeClear ||
|
|
|
|
frameDisposalMethod == FrameBlender::kDisposeRestorePrevious)
|
2014-08-22 13:49:54 -07:00
|
|
|
mAnim->SetFirstFrameRefreshArea(firstFrame->GetRect());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Calculate firstFrameRefreshArea
|
|
|
|
// Some gifs are huge but only have a small area that they animate
|
|
|
|
// We only need to refresh that small area when Frame 0 comes around again
|
2013-07-15 11:38:59 -07:00
|
|
|
mAnim->UnionFirstFrameRefreshArea(frame->GetRect());
|
2013-03-29 13:14:19 -07:00
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
rv = InternalAddFrameHelper(framenum, frame, imageData, imageLength,
|
2013-02-27 11:23:08 -08:00
|
|
|
paletteData, paletteLength, aRetFrame);
|
2013-03-29 13:14:19 -07:00
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-08-13 09:35:32 -07:00
|
|
|
bool
|
2014-03-04 20:48:48 -08:00
|
|
|
RasterImage::ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame)
|
2012-08-13 09:35:32 -07:00
|
|
|
{
|
|
|
|
if (mFrameDecodeFlags == (aNewFlags & DECODE_FLAGS_MASK))
|
|
|
|
return true; // Not asking very much of us here.
|
|
|
|
|
|
|
|
if (mDecoded) {
|
2014-03-04 20:48:48 -08:00
|
|
|
// If the requested frame is opaque and the current and new decode flags
|
|
|
|
// only differ in the premultiply alpha bit then we can use the existing
|
|
|
|
// frame, we don't need to discard and re-decode.
|
|
|
|
uint32_t currentNonAlphaFlags =
|
|
|
|
(mFrameDecodeFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
|
|
|
|
uint32_t newNonAlphaFlags =
|
|
|
|
(aNewFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
|
|
|
|
if (currentNonAlphaFlags == newNonAlphaFlags && FrameIsOpaque(aWhichFrame)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-08-13 09:35:32 -07:00
|
|
|
// if we can't discard, then we're screwed; we have no way
|
|
|
|
// to re-decode. Similarly if we aren't allowed to do a sync
|
|
|
|
// decode.
|
|
|
|
if (!(aNewFlags & FLAG_SYNC_DECODE))
|
|
|
|
return false;
|
2014-01-21 15:19:22 -08:00
|
|
|
if (!CanForciblyDiscardAndRedecode())
|
2012-08-13 09:35:32 -07:00
|
|
|
return false;
|
|
|
|
ForceDiscard();
|
|
|
|
}
|
|
|
|
|
|
|
|
mFrameDecodeFlags = aNewFlags & DECODE_FLAGS_MASK;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2013-08-25 00:19:42 -07:00
|
|
|
RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation)
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-12-17 14:04:32 -08:00
|
|
|
mDecodingMonitor.AssertCurrentThreadIn();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Ensure that we have positive values
|
|
|
|
// XXX - Why isn't the size unsigned? Should this be changed?
|
|
|
|
if ((aWidth < 0) || (aHeight < 0))
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
|
|
|
// if we already have a size, check the new size against the old one
|
2012-05-19 12:32:37 -07:00
|
|
|
if (!mMultipart && mHasSize &&
|
2013-08-25 00:19:42 -07:00
|
|
|
((aWidth != mSize.width) ||
|
|
|
|
(aHeight != mSize.height) ||
|
|
|
|
(aOrientation != mOrientation))) {
|
2012-05-19 12:32:37 -07:00
|
|
|
NS_WARNING("Image changed size on redecode! This should not happen!");
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2011-05-11 02:46:59 -07:00
|
|
|
// Make the decoder aware of the error so that it doesn't try to call
|
|
|
|
// FinishInternal during ShutdownDecoder.
|
|
|
|
if (mDecoder)
|
|
|
|
mDecoder->PostResizeError();
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
DoError();
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the size and flag that we have it
|
|
|
|
mSize.SizeTo(aWidth, aHeight);
|
2013-08-25 00:19:42 -07:00
|
|
|
mOrientation = aOrientation;
|
2011-10-17 07:59:28 -07:00
|
|
|
mHasSize = true;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
mFrameBlender.SetSize(mSize);
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY,
|
|
|
|
int32_t aWidth, int32_t aHeight,
|
2014-04-19 18:28:38 -07:00
|
|
|
SurfaceFormat aFormat,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint8_t aPaletteDepth,
|
|
|
|
uint8_t **imageData, uint32_t *imageLength,
|
2013-02-27 11:23:08 -08:00
|
|
|
uint32_t **paletteData, uint32_t *paletteLength,
|
|
|
|
imgFrame** aRetFrame)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(imageData);
|
|
|
|
NS_ENSURE_ARG_POINTER(imageLength);
|
2013-02-27 11:23:08 -08:00
|
|
|
NS_ENSURE_ARG_POINTER(aRetFrame);
|
2013-06-17 13:49:04 -07:00
|
|
|
NS_ABORT_IF_FALSE(aFrameNum <= GetNumFrames(), "Invalid frame index!");
|
2011-07-14 11:47:43 -07:00
|
|
|
|
|
|
|
if (aPaletteDepth > 0) {
|
|
|
|
NS_ENSURE_ARG_POINTER(paletteData);
|
|
|
|
NS_ENSURE_ARG_POINTER(paletteLength);
|
|
|
|
}
|
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
if (aFrameNum > GetNumFrames())
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
|
|
|
// Adding a frame that doesn't already exist.
|
2013-06-17 13:49:04 -07:00
|
|
|
if (aFrameNum == GetNumFrames()) {
|
2013-03-29 13:14:19 -07:00
|
|
|
return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
|
2011-07-14 11:47:43 -07:00
|
|
|
aPaletteDepth, imageData, imageLength,
|
2013-02-27 11:23:08 -08:00
|
|
|
paletteData, paletteLength, aRetFrame);
|
2013-06-17 13:49:04 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> frame = mFrameBlender.RawGetFrame(aFrameNum);
|
2013-06-17 13:49:04 -07:00
|
|
|
if (!frame) {
|
2013-03-29 13:14:19 -07:00
|
|
|
return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
|
2011-07-14 11:47:43 -07:00
|
|
|
aPaletteDepth, imageData, imageLength,
|
2013-02-27 11:23:08 -08:00
|
|
|
paletteData, paletteLength, aRetFrame);
|
2013-06-17 13:49:04 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
|
|
|
// See if we can re-use the frame that already exists.
|
|
|
|
nsIntRect rect = frame->GetRect();
|
2010-12-07 18:20:52 -08:00
|
|
|
if (rect.x == aX && rect.y == aY && rect.width == aWidth &&
|
2011-07-14 11:47:43 -07:00
|
|
|
rect.height == aHeight && frame->GetFormat() == aFormat &&
|
|
|
|
frame->GetPaletteDepth() == aPaletteDepth) {
|
2010-12-07 18:20:52 -08:00
|
|
|
frame->GetImageData(imageData, imageLength);
|
2011-07-14 11:47:43 -07:00
|
|
|
if (paletteData) {
|
|
|
|
frame->GetPaletteData(paletteData, paletteLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can re-use the frame if it has image data.
|
|
|
|
if (*imageData && paletteData && *paletteData) {
|
2014-08-22 13:49:54 -07:00
|
|
|
frame.forget(aRetFrame);
|
2011-07-14 11:47:43 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (*imageData && !paletteData) {
|
2014-08-22 13:49:54 -07:00
|
|
|
frame.forget(aRetFrame);
|
2010-12-07 18:20:52 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2012-05-19 12:32:37 -07:00
|
|
|
// Not reusable, so replace the frame directly.
|
2012-09-26 08:33:06 -07:00
|
|
|
|
|
|
|
// We know this frame is already locked, because it's the one we're currently
|
|
|
|
// writing to.
|
|
|
|
frame->UnlockImageData();
|
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
mFrameBlender.RemoveFrame(aFrameNum);
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> newFrame(new imgFrame());
|
2014-09-14 15:22:45 -07:00
|
|
|
nsIntRect frameRect(aX, aY, aWidth, aHeight);
|
|
|
|
nsresult rv = newFrame->InitForDecoder(frameRect, aFormat, aPaletteDepth);
|
2012-05-19 12:32:37 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-08-22 13:49:54 -07:00
|
|
|
return InternalAddFrameHelper(aFrameNum, newFrame, imageData, imageLength,
|
|
|
|
paletteData, paletteLength, aRetFrame);
|
2011-07-14 11:47:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
|
|
|
|
int32_t aWidth, int32_t aHeight,
|
2014-04-19 18:28:38 -07:00
|
|
|
SurfaceFormat aFormat,
|
2013-02-27 11:23:08 -08:00
|
|
|
uint8_t** imageData, uint32_t* imageLength,
|
|
|
|
imgFrame** aFrame)
|
2011-07-14 11:47:43 -07:00
|
|
|
{
|
|
|
|
return EnsureFrame(aFramenum, aX, aY, aWidth, aHeight, aFormat,
|
|
|
|
/* aPaletteDepth = */ 0, imageData, imageLength,
|
2012-07-30 07:20:58 -07:00
|
|
|
/* aPaletteData = */ nullptr,
|
2013-02-27 11:23:08 -08:00
|
|
|
/* aPaletteLength = */ nullptr,
|
|
|
|
aFrame);
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2012-03-23 15:10:50 -07:00
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult)
|
2012-03-23 15:10:50 -07:00
|
|
|
{
|
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
NS_ABORT_IF_FALSE(aFrameNum < GetNumFrames(), "Invalid frame index!");
|
|
|
|
if (aFrameNum >= GetNumFrames())
|
2012-03-23 15:10:50 -07:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> frame = mFrameBlender.RawGetFrame(aFrameNum);
|
2012-03-23 15:10:50 -07:00
|
|
|
NS_ABORT_IF_FALSE(frame, "Calling SetFrameAsNonPremult on frame that doesn't exist!");
|
|
|
|
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
frame->SetAsNonPremult(aIsNonPremult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::DecodingComplete()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Flag that we're done decoding.
|
|
|
|
// XXX - these should probably be combined when we fix animated image
|
|
|
|
// discarding with bug 500402.
|
2011-10-17 07:59:28 -07:00
|
|
|
mDecoded = true;
|
|
|
|
mHasBeenDecoded = true;
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// We now have one of the qualifications for discarding. Re-evaluate.
|
|
|
|
if (CanDiscard()) {
|
2010-07-01 10:39:44 -07:00
|
|
|
NS_ABORT_IF_FALSE(!DiscardingActive(),
|
2009-09-12 15:44:18 -07:00
|
|
|
"We shouldn't have been discardable before this");
|
2010-08-13 21:09:49 -07:00
|
|
|
rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
|
2014-09-18 19:26:01 -07:00
|
|
|
// If there's only 1 frame, mark it as optimizable. Optimizing animated images
|
2009-09-12 15:44:18 -07:00
|
|
|
// is not supported.
|
|
|
|
//
|
|
|
|
// We don't optimize the frame for multipart images because we reuse
|
|
|
|
// the frame.
|
2013-06-17 13:49:04 -07:00
|
|
|
if ((GetNumFrames() == 1) && !mMultipart) {
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> firstFrame = mFrameBlender.RawGetFrame(0);
|
2014-09-18 19:26:01 -07:00
|
|
|
firstFrame->SetOptimizable();
|
2014-02-24 19:37:51 -08:00
|
|
|
if (DiscardingEnabled() && CanForciblyDiscard()) {
|
2014-08-22 13:49:54 -07:00
|
|
|
firstFrame->SetDiscardable();
|
2014-02-24 19:37:51 -08:00
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2013-04-03 19:19:38 -07:00
|
|
|
// Double-buffer our frame in the multipart case, since we'll start decoding
|
2013-06-17 13:49:04 -07:00
|
|
|
// into the first frame again immediately and this produces severe tearing.
|
2013-04-03 19:19:38 -07:00
|
|
|
if (mMultipart) {
|
2013-06-17 13:49:04 -07:00
|
|
|
if (GetNumFrames() == 1) {
|
|
|
|
mMultipartDecodedFrame = mFrameBlender.SwapFrame(GetCurrentFrameIndex(),
|
|
|
|
mMultipartDecodedFrame);
|
2013-04-03 19:19:38 -07:00
|
|
|
} else {
|
|
|
|
// Don't double buffer for animated multipart images. It entails more
|
|
|
|
// complexity and it's not really needed since we already are smart about
|
|
|
|
// not displaying the still-decoding frame of an animated image. We may
|
|
|
|
// have already stored an extra frame, though, so we'll release it here.
|
2013-06-17 13:49:04 -07:00
|
|
|
mMultipartDecodedFrame = nullptr;
|
2013-04-03 19:19:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
if (mAnim) {
|
|
|
|
mAnim->SetDoneDecoding(true);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::SetAnimationMode(uint16_t aAnimationMode)
|
|
|
|
{
|
|
|
|
if (mAnim) {
|
|
|
|
mAnim->SetAnimationMode(aAnimationMode);
|
|
|
|
}
|
|
|
|
return SetAnimationModeInternal(aAnimationMode);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//******************************************************************************
|
2010-09-07 17:33:02 -07:00
|
|
|
/* void StartAnimation () */
|
|
|
|
nsresult
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::StartAnimation()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-09-07 17:33:02 -07:00
|
|
|
NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
|
|
|
|
|
2011-07-23 11:49:00 -07:00
|
|
|
EnsureAnimExists();
|
2010-09-07 17:33:02 -07:00
|
|
|
|
2014-09-26 18:50:24 -07:00
|
|
|
nsRefPtr<imgFrame> currentFrame = LookupFrameNoDecode(GetCurrentFrameIndex());
|
2013-09-20 05:12:10 -07:00
|
|
|
// A timeout of -1 means we should display this frame forever.
|
2014-09-12 18:29:27 -07:00
|
|
|
if (currentFrame &&
|
|
|
|
mFrameBlender.GetTimeoutForFrame(GetCurrentFrameIndex()) < 0) {
|
2013-09-20 05:12:10 -07:00
|
|
|
mAnimationFinished = true;
|
|
|
|
return NS_ERROR_ABORT;
|
|
|
|
}
|
2011-11-09 13:39:16 -08:00
|
|
|
|
2013-09-20 05:12:10 -07:00
|
|
|
if (mAnim) {
|
2011-11-09 13:39:16 -08:00
|
|
|
// We need to set the time that this initial frame was first displayed, as
|
|
|
|
// this is used in AdvanceFrame().
|
2013-07-15 11:38:59 -07:00
|
|
|
mAnim->InitAnimationFrameTimeIfNecessary();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2013-03-29 13:14:19 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void stopAnimation (); */
|
2010-09-07 17:33:02 -07:00
|
|
|
nsresult
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::StopAnimation()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-09-07 17:33:02 -07:00
|
|
|
NS_ABORT_IF_FALSE(mAnimating, "Should be animating!");
|
|
|
|
|
2013-09-20 05:12:10 -07:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mError) {
|
|
|
|
rv = NS_ERROR_FAILURE;
|
|
|
|
} else {
|
|
|
|
mAnim->SetAnimationFrameTime(TimeStamp());
|
|
|
|
}
|
2013-09-03 13:20:15 -07:00
|
|
|
|
2013-09-20 05:12:10 -07:00
|
|
|
mAnimating = false;
|
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void resetAnimation (); */
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::ResetAnimation()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2013-03-29 13:14:19 -07:00
|
|
|
if (mAnimationMode == kDontAnimMode ||
|
2013-07-15 11:38:59 -07:00
|
|
|
!mAnim || mAnim->GetCurrentAnimationFrameIndex() == 0)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mAnimationFinished = false;
|
2011-03-31 14:05:31 -07:00
|
|
|
|
2010-09-07 17:33:02 -07:00
|
|
|
if (mAnimating)
|
|
|
|
StopAnimation();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
mFrameBlender.ResetAnimation();
|
2013-09-20 05:12:10 -07:00
|
|
|
mAnim->ResetAnimation();
|
2013-06-17 13:49:04 -07:00
|
|
|
|
2012-09-24 13:31:30 -07:00
|
|
|
UpdateImageContainer();
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
// Note - We probably want to kick off a redecode somewhere around here when
|
|
|
|
// we fix bug 500402.
|
|
|
|
|
2013-09-03 13:20:15 -07:00
|
|
|
// Update display
|
2014-11-14 20:10:47 -08:00
|
|
|
if (mProgressTracker) {
|
2013-07-15 11:38:59 -07:00
|
|
|
nsIntRect rect = mAnim->GetFirstFrameRefreshArea();
|
2014-11-14 20:10:47 -08:00
|
|
|
mProgressTracker->SyncNotifyProgress(NoProgress, rect);
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-09-20 05:12:10 -07:00
|
|
|
// Start the animation again. It may not have been running before, if
|
|
|
|
// mAnimationFinished was true before entering this function.
|
|
|
|
EvaluateAnimation();
|
2010-09-07 17:33:02 -07:00
|
|
|
|
2008-03-19 22:54:30 -07:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-05-17 13:57:20 -07:00
|
|
|
//******************************************************************************
|
2013-09-03 13:20:15 -07:00
|
|
|
// [notxpcom] void setAnimationStartTime ([const] in TimeStamp aTime);
|
2013-05-17 13:57:20 -07:00
|
|
|
NS_IMETHODIMP_(void)
|
2014-06-16 15:25:43 -07:00
|
|
|
RasterImage::SetAnimationStartTime(const TimeStamp& aTime)
|
2013-05-17 13:57:20 -07:00
|
|
|
{
|
2013-09-03 13:20:15 -07:00
|
|
|
if (mError || mAnimationMode == kDontAnimMode || mAnimating || !mAnim)
|
2013-05-17 13:57:20 -07:00
|
|
|
return;
|
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
mAnim->SetAnimationFrameTime(aTime);
|
2013-05-17 13:57:20 -07:00
|
|
|
}
|
|
|
|
|
2013-04-25 15:58:20 -07:00
|
|
|
NS_IMETHODIMP_(float)
|
|
|
|
RasterImage::GetFrameIndex(uint32_t aWhichFrame)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument");
|
|
|
|
return (aWhichFrame == FRAME_FIRST || !mAnim)
|
|
|
|
? 0.0f
|
2013-07-15 11:38:59 -07:00
|
|
|
: mAnim->GetCurrentAnimationFrameIndex();
|
2013-04-25 15:58:20 -07:00
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
void
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::SetLoopCount(int32_t aLoopCount)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
2010-08-13 21:09:49 -07:00
|
|
|
return;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
if (mAnim) {
|
2013-12-06 01:45:24 -08:00
|
|
|
// No need to set this if we're not an animation
|
|
|
|
mFrameBlender.SetLoopCount(aLoopCount);
|
2013-07-15 11:38:59 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2014-06-26 16:02:04 -07:00
|
|
|
NS_IMETHODIMP_(nsIntRect)
|
|
|
|
RasterImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
|
|
|
|
{
|
|
|
|
return aRect;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
2007-10-18 17:36:34 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aBuffer);
|
|
|
|
nsresult rv = NS_OK;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We should not call this if we're not initialized
|
|
|
|
NS_ABORT_IF_FALSE(mInitialized, "Calling AddSourceData() on uninitialized "
|
2010-08-13 21:09:49 -07:00
|
|
|
"RasterImage!");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We should not call this if we're already finished adding source data
|
|
|
|
NS_ABORT_IF_FALSE(!mHasSourceData, "Calling AddSourceData() after calling "
|
|
|
|
"sourceDataComplete()!");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2012-07-21 18:07:15 -07:00
|
|
|
// Image is already decoded, we shouldn't be getting data, but it could
|
|
|
|
// be extra garbage data at the end of a file.
|
|
|
|
if (mDecoded) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-05-19 12:32:37 -07:00
|
|
|
// Starting a new part's frames, let's clean up before we add any
|
|
|
|
// This needs to happen just before we start getting EnsureFrame() call(s),
|
|
|
|
// so that there's no gap for anything to miss us.
|
2014-10-15 13:52:20 -07:00
|
|
|
if (mMultipart && (!mDecoder || mDecoder->BytesDecoded() == 0)) {
|
2012-05-19 12:32:37 -07:00
|
|
|
// Our previous state may have been animated, so let's clean up
|
2013-09-20 05:12:10 -07:00
|
|
|
if (mAnimating)
|
2012-05-19 12:32:37 -07:00
|
|
|
StopAnimation();
|
|
|
|
mAnimationFinished = false;
|
|
|
|
if (mAnim) {
|
2012-07-30 07:20:58 -07:00
|
|
|
mAnim = nullptr;
|
2012-05-19 12:32:37 -07:00
|
|
|
}
|
|
|
|
// If there's only one frame, this could cause flickering
|
2013-06-17 13:49:04 -07:00
|
|
|
int old_frame_count = GetNumFrames();
|
2012-05-19 12:32:37 -07:00
|
|
|
if (old_frame_count > 1) {
|
2013-06-17 13:49:04 -07:00
|
|
|
mFrameBlender.ClearFrames();
|
2012-05-19 12:32:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-01 11:36:39 -08:00
|
|
|
// If we're not storing source data and we've previously gotten the size,
|
|
|
|
// write the data directly to the decoder. (If we haven't gotten the size,
|
|
|
|
// we'll queue up the data and write it out when we do.)
|
|
|
|
if (!StoringSourceData() && mHasSize) {
|
2013-12-17 14:04:32 -08:00
|
|
|
rv = WriteToDecoder(aBuffer, aCount, DECODE_SYNC);
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2010-08-25 13:11:09 -07:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
rv = FinishedSomeDecoding();
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Otherwise, we're storing data in the source buffer
|
|
|
|
else {
|
|
|
|
|
|
|
|
// Store the data
|
|
|
|
char *newElem = mSourceData.AppendElements(aBuffer, aCount);
|
|
|
|
if (!newElem)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
if (mDecoder) {
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodePool::Singleton()->RequestDecode(this);
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Statistics
|
|
|
|
total_source_bytes += aCount;
|
|
|
|
if (mDiscardable)
|
|
|
|
discardable_source_bytes += aCount;
|
2012-10-29 16:32:10 -07:00
|
|
|
PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
2010-08-13 21:09:49 -07:00
|
|
|
("CompressedImageAccounting: Added compressed data to RasterImage %p (%s). "
|
2009-09-12 15:44:18 -07:00
|
|
|
"Total Containers: %d, Discardable containers: %d, "
|
|
|
|
"Total source bytes: %lld, Source bytes for discardable containers %lld",
|
2007-10-18 17:36:34 -07:00
|
|
|
this,
|
2009-09-12 15:44:18 -07:00
|
|
|
mSourceDataMimeType.get(),
|
|
|
|
num_containers,
|
|
|
|
num_discardable_containers,
|
|
|
|
total_source_bytes,
|
|
|
|
discardable_source_bytes));
|
2007-10-18 17:36:34 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note! buf must be declared as char buf[9]; */
|
|
|
|
// just used for logging and hashing the header
|
|
|
|
static void
|
2012-08-09 00:10:11 -07:00
|
|
|
get_header_str (char *buf, char *data, size_t data_len)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int n;
|
|
|
|
static char hex[] = "0123456789abcdef";
|
|
|
|
|
|
|
|
n = data_len < 4 ? data_len : 4;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
buf[i * 2] = hex[(data[i] >> 4) & 0x0f];
|
|
|
|
buf[i * 2 + 1] = hex[data[i] & 0x0f];
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[i * 2] = 0;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2013-02-13 18:41:10 -08:00
|
|
|
RasterImage::DoImageDataComplete()
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// If we've been called before, ignore. Otherwise, flag that we have everything
|
|
|
|
if (mHasSourceData)
|
2007-10-18 17:36:34 -07:00
|
|
|
return NS_OK;
|
2011-10-17 07:59:28 -07:00
|
|
|
mHasSourceData = true;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
// If there's a decoder open, synchronously decode the beginning of the image
|
|
|
|
// to check for errors and get the image's size. (If we already have the
|
|
|
|
// image's size, this does nothing.) Then kick off an async decode of the
|
|
|
|
// rest of the image.
|
|
|
|
if (mDecoder) {
|
2013-03-01 15:17:24 -08:00
|
|
|
nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2013-03-01 15:17:24 -08:00
|
|
|
|
|
|
|
// Free up any extra space in the backing buffer
|
|
|
|
mSourceData.Compact();
|
|
|
|
}
|
2013-03-24 12:43:20 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Log header information
|
2012-10-29 16:32:10 -07:00
|
|
|
if (PR_LOG_TEST(GetCompressedImageAccountingLog(), PR_LOG_DEBUG)) {
|
2007-10-18 17:36:34 -07:00
|
|
|
char buf[9];
|
2009-09-12 15:44:18 -07:00
|
|
|
get_header_str(buf, mSourceData.Elements(), mSourceData.Length());
|
2012-10-29 16:32:10 -07:00
|
|
|
PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
2010-08-13 21:09:49 -07:00
|
|
|
("CompressedImageAccounting: RasterImage::SourceDataComplete() - data "
|
2009-09-12 15:44:18 -07:00
|
|
|
"is done for container %p (%s) - header %p is 0x%s (length %d)",
|
2007-10-18 17:36:34 -07:00
|
|
|
this,
|
2009-09-12 15:44:18 -07:00
|
|
|
mSourceDataMimeType.get(),
|
|
|
|
mSourceData.Elements(),
|
2007-10-18 17:36:34 -07:00
|
|
|
buf,
|
2009-09-12 15:44:18 -07:00
|
|
|
mSourceData.Length()));
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We now have one of the qualifications for discarding. Re-evaluate.
|
|
|
|
if (CanDiscard()) {
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-02-13 18:41:10 -08:00
|
|
|
nsresult
|
|
|
|
RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus, bool aLastPart)
|
|
|
|
{
|
|
|
|
nsresult finalStatus = DoImageDataComplete();
|
|
|
|
|
|
|
|
// Give precedence to Necko failure codes.
|
|
|
|
if (NS_FAILED(aStatus))
|
|
|
|
finalStatus = aStatus;
|
|
|
|
|
2013-02-01 17:06:34 -08:00
|
|
|
// We just recorded OnStopRequest; we need to inform our listeners.
|
2013-03-01 15:17:24 -08:00
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2014-11-14 20:10:47 -08:00
|
|
|
FinishedSomeDecoding(eShutdownIntent_Done,
|
|
|
|
nullptr,
|
2014-11-17 14:29:56 -08:00
|
|
|
LoadCompleteProgress(aLastPart, mError, finalStatus));
|
2013-03-01 15:17:24 -08:00
|
|
|
}
|
2013-02-01 17:06:34 -08:00
|
|
|
|
2013-02-13 18:41:10 -08:00
|
|
|
return finalStatus;
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2012-12-17 14:05:18 -08:00
|
|
|
RasterImage::OnImageDataAvailable(nsIRequest*,
|
|
|
|
nsISupports*,
|
|
|
|
nsIInputStream* aInStr,
|
|
|
|
uint64_t,
|
|
|
|
uint32_t aCount)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
2013-03-29 13:14:19 -07:00
|
|
|
|
2012-12-17 14:05:18 -08:00
|
|
|
// WriteToRasterImage always consumes everything it gets
|
|
|
|
// if it doesn't run out of memory
|
|
|
|
uint32_t bytesRead;
|
|
|
|
rv = aInStr->ReadSegments(WriteToRasterImage, this, aCount, &bytesRead);
|
|
|
|
|
2014-08-23 21:47:55 -07:00
|
|
|
NS_ABORT_IF_FALSE(bytesRead == aCount || HasError() || NS_FAILED(rv),
|
|
|
|
"WriteToRasterImage should consume everything if ReadSegments succeeds or "
|
|
|
|
"the image must be in error!");
|
2012-12-17 14:05:18 -08:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
RasterImage::OnNewSourceData()
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// The source data should be complete before calling this
|
|
|
|
NS_ABORT_IF_FALSE(mHasSourceData,
|
|
|
|
"Calling NewSourceData before SourceDataComplete!");
|
|
|
|
if (!mHasSourceData)
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
|
|
|
// Only supported for multipart channels. It wouldn't be too hard to change this,
|
|
|
|
// but it would involve making sure that things worked for decode-on-draw and
|
|
|
|
// discarding. Presently there's no need for this, so we don't.
|
2013-02-01 11:36:39 -08:00
|
|
|
NS_ABORT_IF_FALSE(mMultipart, "NewSourceData only supported for multipart");
|
2009-09-12 15:44:18 -07:00
|
|
|
if (!mMultipart)
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
|
|
|
// We're multipart, so we shouldn't be storing source data
|
|
|
|
NS_ABORT_IF_FALSE(!StoringSourceData(),
|
|
|
|
"Shouldn't be storing source data for multipart");
|
|
|
|
|
|
|
|
// We're not storing the source data and we got SourceDataComplete. We should
|
|
|
|
// have shut down the previous decoder
|
|
|
|
NS_ABORT_IF_FALSE(!mDecoder, "Shouldn't have a decoder in NewSourceData");
|
|
|
|
|
|
|
|
// The decoder was shut down and we didn't flag an error, so we should be decoded
|
|
|
|
NS_ABORT_IF_FALSE(mDecoded, "Should be decoded in NewSourceData");
|
|
|
|
|
|
|
|
// Reset some flags
|
2011-10-17 07:59:28 -07:00
|
|
|
mDecoded = false;
|
|
|
|
mHasSourceData = false;
|
2013-02-01 11:36:39 -08:00
|
|
|
mHasSize = false;
|
|
|
|
mWantFullDecode = true;
|
2014-10-15 16:00:12 -07:00
|
|
|
mDecodeRequest = nullptr;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-07-15 11:38:59 -07:00
|
|
|
if (mAnim) {
|
|
|
|
mAnim->SetDoneDecoding(false);
|
|
|
|
}
|
|
|
|
|
2013-02-01 11:36:39 -08:00
|
|
|
// We always need the size first.
|
|
|
|
rv = InitDecoder(/* aDoSizeDecode = */ true);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::SetSourceSizeHint(uint32_t sizeHint)
|
2010-06-25 11:21:40 -07:00
|
|
|
{
|
|
|
|
if (sizeHint && StoringSourceData())
|
2011-06-08 19:21:53 -07:00
|
|
|
return mSourceData.SetCapacity(sizeHint) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
2010-06-25 11:21:40 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-06-21 13:45:49 -07:00
|
|
|
/********* Methods to implement lazy allocation of nsIProperties object *************/
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::Get(const char *prop, const nsIID & iid, void * *result)
|
2007-06-21 13:45:49 -07:00
|
|
|
{
|
|
|
|
if (!mProperties)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
return mProperties->Get(prop, iid, result);
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::Set(const char *prop, nsISupports *value)
|
2007-06-21 13:45:49 -07:00
|
|
|
{
|
|
|
|
if (!mProperties)
|
|
|
|
mProperties = do_CreateInstance("@mozilla.org/properties;1");
|
|
|
|
if (!mProperties)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
return mProperties->Set(prop, value);
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
RasterImage::Has(const char *prop, bool *_retval)
|
2007-06-21 13:45:49 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
if (!mProperties) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*_retval = false;
|
2007-06-21 13:45:49 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return mProperties->Has(prop, _retval);
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::Undefine(const char *prop)
|
2007-06-21 13:45:49 -07:00
|
|
|
{
|
|
|
|
if (!mProperties)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
return mProperties->Undefine(prop);
|
|
|
|
}
|
|
|
|
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::GetKeys(uint32_t *count, char ***keys)
|
2007-06-21 13:45:49 -07:00
|
|
|
{
|
|
|
|
if (!mProperties) {
|
|
|
|
*count = 0;
|
2012-07-30 07:20:58 -07:00
|
|
|
*keys = nullptr;
|
2007-06-21 13:45:49 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return mProperties->GetKeys(count, keys);
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
|
|
|
void
|
2011-01-12 17:45:13 -08:00
|
|
|
RasterImage::Discard(bool force)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We should be ok for discard
|
2011-01-12 17:45:13 -08:00
|
|
|
NS_ABORT_IF_FALSE(force ? CanForciblyDiscard() : CanDiscard(), "Asked to discard but can't!");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We should never discard when we have an active decoder
|
2010-07-01 10:39:44 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mDecoder, "Asked to discard with open decoder!");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// As soon as an image becomes animated, it becomes non-discardable and any
|
|
|
|
// timers are cancelled.
|
2010-07-01 10:39:44 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// For post-operation logging
|
2013-06-17 13:49:04 -07:00
|
|
|
int old_frame_count = GetNumFrames();
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2013-06-17 13:49:04 -07:00
|
|
|
// Delete all the decoded frames
|
|
|
|
mFrameBlender.Discard();
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2013-04-03 19:19:38 -07:00
|
|
|
// Clear the last decoded multipart frame.
|
|
|
|
mMultipartDecodedFrame = nullptr;
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Flag that we no longer have decoded frames for this image
|
2011-10-17 07:59:28 -07:00
|
|
|
mDecoded = false;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Notify that we discarded
|
2014-11-14 20:10:47 -08:00
|
|
|
if (mProgressTracker)
|
|
|
|
mProgressTracker->OnDiscard();
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
mDecodeRequest = nullptr;
|
2013-02-27 11:23:08 -08:00
|
|
|
|
2012-03-09 15:32:42 -08:00
|
|
|
if (force)
|
|
|
|
DiscardTracker::Remove(&mDiscardTrackerNode);
|
2011-01-12 17:45:13 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Log
|
2012-10-29 16:32:10 -07:00
|
|
|
PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
2009-09-12 15:44:18 -07:00
|
|
|
("CompressedImageAccounting: discarded uncompressed image "
|
2010-08-13 21:09:49 -07:00
|
|
|
"data from RasterImage %p (%s) - %d frames (cached count: %d); "
|
2009-09-12 15:44:18 -07:00
|
|
|
"Total Containers: %d, Discardable containers: %d, "
|
|
|
|
"Total source bytes: %lld, Source bytes for discardable containers %lld",
|
2010-07-01 10:39:44 -07:00
|
|
|
this,
|
|
|
|
mSourceDataMimeType.get(),
|
2007-10-18 17:36:34 -07:00
|
|
|
old_frame_count,
|
2013-06-17 13:49:04 -07:00
|
|
|
GetNumFrames(),
|
2009-09-12 15:44:18 -07:00
|
|
|
num_containers,
|
|
|
|
num_discardable_containers,
|
|
|
|
total_source_bytes,
|
|
|
|
discardable_source_bytes));
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Helper method to determine if we can discard an image
|
2011-08-05 06:57:16 -07:00
|
|
|
bool
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::CanDiscard() {
|
2009-09-12 15:44:18 -07:00
|
|
|
return (DiscardingEnabled() && // Globally enabled...
|
|
|
|
mDiscardable && // ...Enabled at creation time...
|
|
|
|
(mLockCount == 0) && // ...not temporarily disabled...
|
|
|
|
mHasSourceData && // ...have the source data...
|
|
|
|
mDecoded); // ...and have something to discard.
|
|
|
|
}
|
|
|
|
|
2011-08-05 06:57:16 -07:00
|
|
|
bool
|
2011-01-12 17:45:13 -08:00
|
|
|
RasterImage::CanForciblyDiscard() {
|
2011-07-21 11:15:17 -07:00
|
|
|
return mDiscardable && // ...Enabled at creation time...
|
|
|
|
mHasSourceData; // ...have the source data...
|
2011-01-12 17:45:13 -08:00
|
|
|
}
|
|
|
|
|
2014-01-21 15:19:22 -08:00
|
|
|
bool
|
|
|
|
RasterImage::CanForciblyDiscardAndRedecode() {
|
|
|
|
return mDiscardable && // ...Enabled at creation time...
|
|
|
|
mHasSourceData && // ...have the source data...
|
|
|
|
!mDecoder && // Can't discard with an open decoder
|
|
|
|
!mAnim; // Can never discard animated images
|
|
|
|
}
|
|
|
|
|
2010-07-01 10:39:44 -07:00
|
|
|
// Helper method to tell us whether the clock is currently running for
|
|
|
|
// discarding this image. Mainly for assertions.
|
2011-08-05 06:57:16 -07:00
|
|
|
bool
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::DiscardingActive() {
|
2012-03-15 13:30:41 -07:00
|
|
|
return mDiscardTrackerNode.isInList();
|
2010-07-01 10:39:44 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Helper method to determine if we're storing the source data in a buffer
|
|
|
|
// or just writing it directly to the decoder
|
2011-08-05 06:57:16 -07:00
|
|
|
bool
|
2012-02-19 19:51:48 -08:00
|
|
|
RasterImage::StoringSourceData() const {
|
2009-09-12 15:44:18 -07:00
|
|
|
return (mDecodeOnDraw || mDiscardable);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Sets up a decoder for this image. It is an error to call this function
|
|
|
|
// when decoding is already in process (ie - when mDecoder is non-null).
|
2007-10-18 17:36:34 -07:00
|
|
|
nsresult
|
2013-11-20 17:21:51 -08:00
|
|
|
RasterImage::InitDecoder(bool aDoSizeDecode)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
// Ensure that the decoder is not already initialized
|
|
|
|
NS_ABORT_IF_FALSE(!mDecoder, "Calling InitDecoder() while already decoding!");
|
2013-03-29 13:14:19 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We shouldn't be firing up a decoder if we already have the frames decoded
|
|
|
|
NS_ABORT_IF_FALSE(!mDecoded, "Calling InitDecoder() but already decoded!");
|
|
|
|
|
|
|
|
// Since we're not decoded, we should not have a discard timer active
|
2010-07-01 10:39:44 -07:00
|
|
|
NS_ABORT_IF_FALSE(!DiscardingActive(), "Discard Timer active in InitDecoder()!");
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-02-01 17:06:34 -08:00
|
|
|
// Make sure we actually get size before doing a full decode.
|
2013-02-01 11:36:39 -08:00
|
|
|
if (!aDoSizeDecode) {
|
2013-01-31 10:38:24 -08:00
|
|
|
NS_ABORT_IF_FALSE(mHasSize, "Must do a size decode before a full decode!");
|
|
|
|
}
|
|
|
|
|
2010-08-22 19:30:45 -07:00
|
|
|
// Figure out which decoder we want
|
|
|
|
eDecoderType type = GetDecoderType(mSourceDataMimeType.get());
|
|
|
|
CONTAINER_ENSURE_TRUE(type != eDecoderType_unknown, NS_IMAGELIB_ERROR_NO_DECODER);
|
|
|
|
|
|
|
|
// Instantiate the appropriate decoder
|
|
|
|
switch (type) {
|
|
|
|
case eDecoderType_png:
|
2013-01-18 13:47:18 -08:00
|
|
|
mDecoder = new nsPNGDecoder(*this);
|
2010-08-22 19:30:45 -07:00
|
|
|
break;
|
|
|
|
case eDecoderType_gif:
|
2013-01-18 13:47:18 -08:00
|
|
|
mDecoder = new nsGIFDecoder2(*this);
|
2010-08-22 19:30:45 -07:00
|
|
|
break;
|
|
|
|
case eDecoderType_jpeg:
|
2012-11-18 17:18:52 -08:00
|
|
|
// If we have all the data we don't want to waste cpu time doing
|
|
|
|
// a progressive decode
|
2013-01-18 13:47:18 -08:00
|
|
|
mDecoder = new nsJPEGDecoder(*this,
|
2012-11-20 11:27:39 -08:00
|
|
|
mHasBeenDecoded ? Decoder::SEQUENTIAL :
|
|
|
|
Decoder::PROGRESSIVE);
|
2010-08-22 19:30:45 -07:00
|
|
|
break;
|
|
|
|
case eDecoderType_bmp:
|
2013-01-18 13:47:18 -08:00
|
|
|
mDecoder = new nsBMPDecoder(*this);
|
2010-08-22 19:30:45 -07:00
|
|
|
break;
|
|
|
|
case eDecoderType_ico:
|
2013-01-18 13:47:18 -08:00
|
|
|
mDecoder = new nsICODecoder(*this);
|
2010-08-22 19:30:45 -07:00
|
|
|
break;
|
|
|
|
case eDecoderType_icon:
|
2013-01-18 13:47:18 -08:00
|
|
|
mDecoder = new nsIconDecoder(*this);
|
2010-08-22 19:30:45 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_ABORT_IF_FALSE(0, "Shouldn't get here!");
|
|
|
|
}
|
2010-08-11 17:49:50 -07:00
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// If we already have frames, we're probably in the multipart/x-mixed-replace
|
|
|
|
// case. Regardless, we need to lock the last frame. Our invariant is that,
|
|
|
|
// while we have a decoder open, the last frame is always locked.
|
2013-06-17 13:49:04 -07:00
|
|
|
if (GetNumFrames() > 0) {
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
|
2013-02-27 11:23:08 -08:00
|
|
|
curframe->LockImageData();
|
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Initialize the decoder
|
2014-10-15 16:00:12 -07:00
|
|
|
if (!mDecodeRequest) {
|
|
|
|
mDecodeRequest = new DecodeRequest(this);
|
2014-10-15 13:52:22 -07:00
|
|
|
}
|
2010-08-22 19:30:46 -07:00
|
|
|
mDecoder->SetSizeDecode(aDoSizeDecode);
|
2011-01-12 17:45:13 -08:00
|
|
|
mDecoder->SetDecodeFlags(mFrameDecodeFlags);
|
2013-02-01 17:06:30 -08:00
|
|
|
if (!aDoSizeDecode) {
|
|
|
|
// We already have the size; tell the decoder so it can preallocate a
|
|
|
|
// frame. By default, we create an ARGB frame with no offset. If decoders
|
|
|
|
// need a different type, they need to ask for it themselves.
|
|
|
|
mDecoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height,
|
2014-04-19 18:28:38 -07:00
|
|
|
SurfaceFormat::B8G8R8A8);
|
2013-02-27 11:23:08 -08:00
|
|
|
mDecoder->AllocateFrame();
|
2013-02-01 17:06:30 -08:00
|
|
|
}
|
2011-09-27 09:24:03 -07:00
|
|
|
mDecoder->Init();
|
2010-09-12 08:22:31 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2011-09-08 11:05:11 -07:00
|
|
|
if (!aDoSizeDecode) {
|
|
|
|
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
|
|
|
|
mDecodeCount++;
|
|
|
|
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
|
2013-01-03 13:06:08 -08:00
|
|
|
|
|
|
|
if (mDecodeCount > sMaxDecodeCount) {
|
|
|
|
// Don't subtract out 0 from the histogram, because that causes its count
|
|
|
|
// to go negative, which is not kosher.
|
|
|
|
if (sMaxDecodeCount > 0) {
|
|
|
|
Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)->Subtract(sMaxDecodeCount);
|
2013-02-01 11:36:39 -08:00
|
|
|
}
|
2013-01-03 13:06:08 -08:00
|
|
|
sMaxDecodeCount = mDecodeCount;
|
|
|
|
Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)->Add(sMaxDecodeCount);
|
|
|
|
}
|
2011-09-08 11:05:11 -07:00
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Flushes, closes, and nulls-out a decoder. Cleans up any related decoding
|
|
|
|
// state. It is an error to call this function when there is no initialized
|
|
|
|
// decoder.
|
2013-03-29 13:14:19 -07:00
|
|
|
//
|
2009-09-12 15:44:18 -07:00
|
|
|
// aIntent specifies the intent of the shutdown. If aIntent is
|
|
|
|
// eShutdownIntent_Done, an error is flagged if we didn't get what we should
|
2013-02-13 13:41:45 -08:00
|
|
|
// have out of the decode. If aIntent is eShutdownIntent_NotNeeded, we don't
|
2009-09-12 15:44:18 -07:00
|
|
|
// check this. If aIntent is eShutdownIntent_Error, we shut down in error mode.
|
|
|
|
nsresult
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::ShutdownDecoder(eShutdownIntent aIntent)
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
2013-01-18 13:47:18 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-12-17 14:04:31 -08:00
|
|
|
mDecodingMonitor.AssertCurrentThreadIn();
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Ensure that our intent is valid
|
2013-01-10 17:56:51 -08:00
|
|
|
NS_ABORT_IF_FALSE((aIntent >= 0) && (aIntent < eShutdownIntent_AllCount),
|
2009-09-12 15:44:18 -07:00
|
|
|
"Invalid shutdown intent");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Ensure that the decoder is initialized
|
|
|
|
NS_ABORT_IF_FALSE(mDecoder, "Calling ShutdownDecoder() with no active decoder!");
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2010-08-22 19:30:46 -07:00
|
|
|
// Figure out what kind of decode we were doing before we get rid of our decoder
|
|
|
|
bool wasSizeDecode = mDecoder->IsSizeDecode();
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// Finalize the decoder
|
2011-05-11 02:46:59 -07:00
|
|
|
// null out mDecoder, _then_ check for errors on the close (otherwise the
|
|
|
|
// error routine might re-invoke ShutdownDecoder)
|
|
|
|
nsRefPtr<Decoder> decoder = mDecoder;
|
2012-07-30 07:20:58 -07:00
|
|
|
mDecoder = nullptr;
|
2011-05-11 02:46:59 -07:00
|
|
|
|
2012-11-16 11:43:24 -08:00
|
|
|
decoder->Finish(aIntent);
|
2010-08-22 07:13:09 -07:00
|
|
|
|
2014-02-24 19:37:51 -08:00
|
|
|
// Unlock the last frame (if we have any). Our invariant is that, while we
|
|
|
|
// have a decoder open, the last frame is always locked.
|
|
|
|
if (GetNumFrames() > 0) {
|
2014-08-22 13:49:54 -07:00
|
|
|
nsRefPtr<imgFrame> curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
|
2014-02-24 19:37:51 -08:00
|
|
|
curframe->UnlockImageData();
|
|
|
|
}
|
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
// Kill off our decode request, if it's pending. (If not, this call is
|
|
|
|
// harmless.)
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodePool::StopDecoding(this);
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2011-05-11 02:46:59 -07:00
|
|
|
nsresult decoderStatus = decoder->GetDecoderError();
|
2010-09-12 08:22:30 -07:00
|
|
|
if (NS_FAILED(decoderStatus)) {
|
2009-09-12 15:44:18 -07:00
|
|
|
DoError();
|
2010-09-12 08:22:30 -07:00
|
|
|
return decoderStatus;
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We just shut down the decoder. If we didn't get what we want, but expected
|
|
|
|
// to, flag an error
|
2011-07-20 14:52:30 -07:00
|
|
|
bool failed = false;
|
2010-08-22 19:30:46 -07:00
|
|
|
if (wasSizeDecode && !mHasSize)
|
2011-07-20 14:52:30 -07:00
|
|
|
failed = true;
|
2010-08-22 19:30:46 -07:00
|
|
|
if (!wasSizeDecode && !mDecoded)
|
2011-07-20 14:52:30 -07:00
|
|
|
failed = true;
|
2009-09-12 15:44:18 -07:00
|
|
|
if ((aIntent == eShutdownIntent_Done) && failed) {
|
|
|
|
DoError();
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-02-01 11:36:39 -08:00
|
|
|
// If we finished a full decode, and we're not meant to be storing source
|
|
|
|
// data, stop storing it.
|
|
|
|
if (!wasSizeDecode && !StoringSourceData()) {
|
|
|
|
mSourceData.Clear();
|
|
|
|
}
|
|
|
|
|
2007-10-18 17:36:34 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-10-15 19:54:44 -07:00
|
|
|
// Writes the data to the decoder, updating the total number of bytes written.
|
2009-09-12 15:44:18 -07:00
|
|
|
nsresult
|
2013-12-17 14:04:24 -08:00
|
|
|
RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
mDecodingMonitor.AssertCurrentThreadIn();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We should have a decoder
|
|
|
|
NS_ABORT_IF_FALSE(mDecoder, "Trying to write to null decoder!");
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Write
|
2011-05-11 02:46:59 -07:00
|
|
|
nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
|
2013-12-17 14:04:24 -08:00
|
|
|
mDecoder->Write(aBuffer, aCount, aStrategy);
|
2010-02-25 10:14:30 -08:00
|
|
|
|
2011-11-04 10:47:28 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
|
|
|
|
|
|
|
|
return NS_OK;
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// This function is called in situations where it's clear that we want the
|
2014-09-26 18:50:24 -07:00
|
|
|
// frames in decoded form (Draw, LookupFrame, etc). If we're completely decoded,
|
2013-04-05 14:15:05 -07:00
|
|
|
// this method resets the discard timer (if we're discardable), since wanting
|
|
|
|
// the frames now is a good indicator of wanting them again soon. If we're not
|
|
|
|
// decoded, this method kicks off asynchronous decoding to generate the frames.
|
2009-09-12 15:44:18 -07:00
|
|
|
nsresult
|
2014-09-26 18:50:24 -07:00
|
|
|
RasterImage::WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
nsresult rv;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2010-07-01 10:39:44 -07:00
|
|
|
// If we can discard, the clock should be running. Reset it.
|
2009-09-12 15:44:18 -07:00
|
|
|
if (CanDiscard()) {
|
2010-07-01 10:39:44 -07:00
|
|
|
NS_ABORT_IF_FALSE(DiscardingActive(),
|
|
|
|
"Decoded and discardable but discarding not activated!");
|
2010-08-13 21:09:49 -07:00
|
|
|
rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2014-09-26 18:50:24 -07:00
|
|
|
// Request a decode, which does nothing if we're already decoded.
|
|
|
|
if (aShouldSyncNotify) {
|
|
|
|
// We can sync notify, which means we can also sync decode.
|
|
|
|
if (aFlags & FLAG_SYNC_DECODE) {
|
|
|
|
return SyncDecode();
|
|
|
|
}
|
|
|
|
return StartDecoding();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can't sync notify, so do an async decode.
|
|
|
|
return RequestDecodeCore(ASYNCHRONOUS);
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* void requestDecode() */
|
|
|
|
NS_IMETHODIMP
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::RequestDecode()
|
2012-10-04 13:02:15 -07:00
|
|
|
{
|
2013-05-09 06:36:57 -07:00
|
|
|
return RequestDecodeCore(SYNCHRONOUS_NOTIFY);
|
2012-10-04 13:02:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* void startDecode() */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::StartDecoding()
|
|
|
|
{
|
2013-09-28 11:28:42 -07:00
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
return NS_DispatchToMainThread(
|
|
|
|
NS_NewRunnableMethod(this, &RasterImage::StartDecoding));
|
|
|
|
}
|
2013-06-04 15:05:54 -07:00
|
|
|
// Here we are explicitly trading off flashing for responsiveness in the case
|
|
|
|
// that we're redecoding an image (see bug 845147).
|
2013-06-26 13:36:43 -07:00
|
|
|
return RequestDecodeCore(mHasBeenDecoded ?
|
|
|
|
SYNCHRONOUS_NOTIFY : SYNCHRONOUS_NOTIFY_AND_SOME_DECODE);
|
2012-10-04 13:02:15 -07:00
|
|
|
}
|
|
|
|
|
2013-05-22 02:27:02 -07:00
|
|
|
bool
|
|
|
|
RasterImage::IsDecoded()
|
|
|
|
{
|
|
|
|
return mDecoded || mError;
|
|
|
|
}
|
2012-10-04 13:02:15 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
nsresult rv;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2013-04-26 13:43:17 -07:00
|
|
|
// If we're already decoded, there's nothing to do.
|
|
|
|
if (mDecoded)
|
2009-09-19 12:33:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2013-04-26 13:43:17 -07:00
|
|
|
// If we're currently waiting for a new frame, we can't do anything until
|
|
|
|
// that frame is allocated.
|
|
|
|
if (mDecoder && mDecoder->NeedsNewFrame())
|
|
|
|
return NS_OK;
|
|
|
|
|
2013-01-31 10:38:24 -08:00
|
|
|
// If we have a size decoder open, make sure we get the size
|
|
|
|
if (mDecoder && mDecoder->IsSizeDecode()) {
|
2013-03-01 15:17:24 -08:00
|
|
|
nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
|
2013-01-31 10:38:24 -08:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
|
|
|
|
// If we didn't get the size out of the image, we won't until we get more
|
|
|
|
// data, so signal that we want a full decode and give up for now.
|
|
|
|
if (!mHasSize) {
|
|
|
|
mWantFullDecode = true;
|
2013-04-03 19:18:42 -07:00
|
|
|
return NS_OK;
|
2013-01-31 10:38:24 -08:00
|
|
|
}
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2014-08-26 21:02:10 -07:00
|
|
|
// If the image is waiting for decode work to be notified, go ahead and do that.
|
2014-10-15 16:00:12 -07:00
|
|
|
if (mDecodeRequest &&
|
|
|
|
mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE &&
|
2014-08-26 21:02:10 -07:00
|
|
|
aDecodeType == SYNCHRONOUS_NOTIFY) {
|
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
|
|
|
nsresult rv = FinishedSomeDecoding();
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're fully decoded, we have nothing to do. We need this check after
|
|
|
|
// DecodeUntilSizeAvailable and FinishedSomeDecoding because they can result
|
|
|
|
// in us finishing an in-progress decode (or kicking off and finishing a
|
|
|
|
// synchronous decode if we're already waiting on a full decode).
|
|
|
|
if (mDecoded) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we've already got a full decoder running, and have already decoded
|
|
|
|
// some bytes, we have nothing to do if we haven't been asked to do some
|
|
|
|
// sync decoding
|
2014-10-15 13:52:20 -07:00
|
|
|
if (mDecoder && !mDecoder->IsSizeDecode() && mDecoder->BytesDecoded() > 0 &&
|
2014-08-26 21:02:10 -07:00
|
|
|
aDecodeType != SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2013-04-26 13:43:17 -07:00
|
|
|
|
2013-10-16 08:56:08 -07:00
|
|
|
// If we don't have any bytes to flush to the decoder, we can't do anything.
|
2014-10-15 13:52:20 -07:00
|
|
|
// mDecoder->BytesDecoded() can be bigger than mSourceData.Length() if we're
|
|
|
|
// not storing the source data.
|
|
|
|
if (mDecoder && mDecoder->BytesDecoded() > mSourceData.Length()) {
|
2013-10-16 08:56:08 -07:00
|
|
|
return NS_OK;
|
2014-10-15 13:52:20 -07:00
|
|
|
}
|
2013-10-16 08:56:08 -07:00
|
|
|
|
2014-08-26 21:02:10 -07:00
|
|
|
// After acquiring the lock we may have finished some more decoding, so
|
|
|
|
// we need to repeat the following three checks after getting the lock.
|
|
|
|
|
2013-04-26 13:43:17 -07:00
|
|
|
// If the image is waiting for decode work to be notified, go ahead and do that.
|
2014-10-15 16:00:12 -07:00
|
|
|
if (mDecodeRequest &&
|
|
|
|
mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE &&
|
|
|
|
aDecodeType != ASYNCHRONOUS) {
|
2013-04-26 13:43:17 -07:00
|
|
|
nsresult rv = FinishedSomeDecoding();
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're fully decoded, we have nothing to do. We need this check after
|
|
|
|
// DecodeUntilSizeAvailable and FinishedSomeDecoding because they can result
|
|
|
|
// in us finishing an in-progress decode (or kicking off and finishing a
|
|
|
|
// synchronous decode if we're already waiting on a full decode).
|
|
|
|
if (mDecoded) {
|
2013-02-01 11:36:39 -08:00
|
|
|
return NS_OK;
|
2013-04-26 13:43:17 -07:00
|
|
|
}
|
2013-02-01 11:36:39 -08:00
|
|
|
|
2013-04-26 13:43:17 -07:00
|
|
|
// If we've already got a full decoder running, and have already
|
2014-10-15 13:52:20 -07:00
|
|
|
// decoded some bytes, we have nothing to do.
|
|
|
|
if (mDecoder && !mDecoder->IsSizeDecode() && mDecoder->BytesDecoded() > 0) {
|
2013-04-26 13:43:17 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2011-01-12 17:45:13 -08:00
|
|
|
// If we have a size decode open, interrupt it and shut it down; or if
|
|
|
|
// the decoder has different flags than what we need
|
2013-02-01 11:36:39 -08:00
|
|
|
if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
|
2013-02-01 17:06:34 -08:00
|
|
|
nsresult rv = FinishedSomeDecoding(eShutdownIntent_NotNeeded);
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
// If we don't have a decoder, create one
|
2009-09-12 15:44:18 -07:00
|
|
|
if (!mDecoder) {
|
2010-08-22 19:30:46 -07:00
|
|
|
rv = InitDecoder(/* aDoSizeDecode = */ false);
|
2013-03-22 15:46:20 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2013-03-22 15:46:20 -07:00
|
|
|
rv = FinishedSomeDecoding();
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2014-10-15 13:52:20 -07:00
|
|
|
MOZ_ASSERT(mDecoder);
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// If we've read all the data we have, we're done
|
2014-10-15 13:52:20 -07:00
|
|
|
if (mHasSourceData && mDecoder->BytesDecoded() == mSourceData.Length()) {
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_OK;
|
2014-10-15 13:52:20 -07:00
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2012-08-13 11:12:15 -07:00
|
|
|
// If we can do decoding now, do so. Small images will decode completely,
|
|
|
|
// large images will decode a bit and post themselves to the event loop
|
|
|
|
// to finish decoding.
|
2014-11-14 20:06:21 -08:00
|
|
|
if (!mDecoded && mHasSourceData && aDecodeType == SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) {
|
2014-05-23 14:12:29 -07:00
|
|
|
PROFILER_LABEL_PRINTF("RasterImage", "DecodeABitOf",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS, "%s", GetURIString().get());
|
|
|
|
|
2013-12-17 14:04:24 -08:00
|
|
|
DecodePool::Singleton()->DecodeABitOf(this, DECODE_SYNC);
|
2012-08-13 11:12:15 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-08-26 15:54:21 -07:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
if (!mDecoded) {
|
|
|
|
// If we get this far, dispatch the worker. We do this instead of starting
|
|
|
|
// any immediate decoding to guarantee that all our decode notifications are
|
|
|
|
// dispatched asynchronously, and to ensure we stay responsive.
|
|
|
|
DecodePool::Singleton()->RequestDecode(this);
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
|
|
|
return NS_OK;
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Synchronously decodes as much data as possible
|
|
|
|
nsresult
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::SyncDecode()
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2014-05-23 14:12:29 -07:00
|
|
|
PROFILER_LABEL_PRINTF("RasterImage", "SyncDecode",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS, "%s", GetURIString().get());
|
2012-10-03 13:36:26 -07:00
|
|
|
|
2013-01-31 10:38:24 -08:00
|
|
|
// If we have a size decoder open, make sure we get the size
|
|
|
|
if (mDecoder && mDecoder->IsSizeDecode()) {
|
2013-03-01 15:17:24 -08:00
|
|
|
nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
|
2013-01-31 10:38:24 -08:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
|
|
|
|
// If we didn't get the size out of the image, we won't until we get more
|
|
|
|
// data, so signal that we want a full decode and give up for now.
|
|
|
|
if (!mHasSize) {
|
|
|
|
mWantFullDecode = true;
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2013-07-26 11:57:41 -07:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
if (mDecodeRequest) {
|
|
|
|
// If the image is waiting for decode work to be notified, go ahead and do that.
|
|
|
|
if (mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
|
|
|
|
nsresult rv = FinishedSomeDecoding();
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
2013-07-26 11:57:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
|
2013-01-31 10:38:24 -08:00
|
|
|
// If we're decoded already, or decoding until the size was available
|
|
|
|
// finished us as a side-effect, no worries
|
|
|
|
if (mDecoded)
|
|
|
|
return NS_OK;
|
|
|
|
|
2013-05-21 22:38:06 -07:00
|
|
|
// If we don't have any bytes to flush to the decoder, we can't do anything.
|
2014-10-15 13:52:20 -07:00
|
|
|
// mDecoder->BytesDecoded() can be bigger than mSourceData.Length() if we're
|
|
|
|
// not storing the source data.
|
|
|
|
if (mDecoder && mDecoder->BytesDecoded() > mSourceData.Length()) {
|
2013-05-21 22:38:06 -07:00
|
|
|
return NS_OK;
|
2014-10-15 13:52:20 -07:00
|
|
|
}
|
2013-05-21 22:38:06 -07:00
|
|
|
|
2013-01-31 10:38:24 -08:00
|
|
|
// If we have a decoder open with different flags than what we need, shut it
|
|
|
|
// down
|
|
|
|
if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
|
2013-02-01 17:06:34 -08:00
|
|
|
nsresult rv = FinishedSomeDecoding(eShutdownIntent_NotNeeded);
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2014-01-21 15:19:20 -08:00
|
|
|
|
|
|
|
if (mDecoded) {
|
|
|
|
// If we've finished decoding we need to discard so we can re-decode
|
|
|
|
// with the new flags. If we can't discard then there isn't
|
|
|
|
// anything we can do.
|
2014-01-21 15:19:22 -08:00
|
|
|
if (!CanForciblyDiscardAndRedecode())
|
2014-01-21 15:19:20 -08:00
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
ForceDiscard();
|
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
2014-11-18 12:06:27 -08:00
|
|
|
// If we're currently waiting on a new frame for this image, create it now.
|
2013-02-27 11:23:08 -08:00
|
|
|
if (mDecoder && mDecoder->NeedsNewFrame()) {
|
|
|
|
mDecoder->AllocateFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have a decoder, create one
|
2009-09-12 15:44:18 -07:00
|
|
|
if (!mDecoder) {
|
2013-11-20 17:21:51 -08:00
|
|
|
rv = InitDecoder(/* aDoSizeDecode = */ false);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
|
2014-10-15 13:52:20 -07:00
|
|
|
MOZ_ASSERT(mDecoder);
|
|
|
|
|
2013-12-17 14:04:24 -08:00
|
|
|
// Write everything we have
|
2014-10-15 13:52:20 -07:00
|
|
|
rv = DecodeSomeData(mSourceData.Length() - mDecoder->BytesDecoded(),
|
|
|
|
DECODE_SYNC);
|
2013-12-17 14:04:24 -08:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-03-22 15:46:20 -07:00
|
|
|
rv = FinishedSomeDecoding();
|
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
2013-11-20 17:21:51 -08:00
|
|
|
|
|
|
|
// If our decoder's still open, there's still work to be done.
|
2013-03-22 15:46:20 -07:00
|
|
|
if (mDecoder) {
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodePool::Singleton()->RequestDecode(this);
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 02:46:59 -07:00
|
|
|
// All good if no errors!
|
|
|
|
return mError ? NS_ERROR_FAILURE : NS_OK;
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2013-03-24 09:37:21 -07:00
|
|
|
bool
|
2014-09-19 14:53:29 -07:00
|
|
|
RasterImage::CanScale(GraphicsFilter aFilter,
|
|
|
|
const nsIntSize& aSize,
|
|
|
|
uint32_t aFlags)
|
2012-10-03 11:29:42 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
#ifndef MOZ_ENABLE_SKIA
|
|
|
|
// The high-quality scaler requires Skia.
|
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
// Check basic requirements: HQ downscaling is enabled, we're decoded, the
|
|
|
|
// flags allow us to do it, and a 'good' filter is being used. The flags may
|
|
|
|
// ask us not to scale because the caller isn't drawing to the window. If
|
|
|
|
// we're drawing to something else (e.g. a canvas) we usually have no way of
|
|
|
|
// updating what we've drawn, so HQ scaling is useless.
|
2014-09-22 14:30:20 -07:00
|
|
|
if (!gfxPrefs::ImageHQDownscalingEnabled() || !mDecoded ||
|
2014-09-19 14:53:29 -07:00
|
|
|
!(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING) ||
|
|
|
|
aFilter != GraphicsFilter::FILTER_GOOD) {
|
2012-10-03 11:29:42 -07:00
|
|
|
return false;
|
2013-03-24 09:37:21 -07:00
|
|
|
}
|
|
|
|
|
2013-01-21 08:37:54 -08:00
|
|
|
// We don't use the scaler for animated or multipart images to avoid doing a
|
|
|
|
// bunch of work on an image that just gets thrown away.
|
2014-09-19 14:53:29 -07:00
|
|
|
if (mAnim || mMultipart) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-10-10 08:35:23 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// If target size is 1:1 with original, don't scale.
|
|
|
|
if (aSize == mSize) {
|
|
|
|
return false;
|
2014-09-14 23:17:28 -07:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// To save memory, don't quality upscale images bigger than the limit.
|
|
|
|
if (aSize.width > mSize.width || aSize.height > mSize.height) {
|
|
|
|
uint32_t scaledSize = static_cast<uint32_t>(aSize.width * aSize.height);
|
2014-09-22 14:30:20 -07:00
|
|
|
if (scaledSize > gfxPrefs::ImageHQUpscalingMaxSize()) {
|
2014-09-19 14:53:29 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-09-16 19:04:53 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// There's no point in scaling if we can't store the result.
|
|
|
|
if (!SurfaceCache::CanHold(aSize.ToIntSize())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-22 14:30:20 -07:00
|
|
|
// XXX(seth): It's not clear what this check buys us over
|
|
|
|
// gfxPrefs::ImageHQUpscalingMaxSize().
|
2014-09-19 14:53:29 -07:00
|
|
|
// The default value of this pref is 1000, which means that we never upscale.
|
|
|
|
// If that's all it's getting us, I'd rather we just forbid that explicitly.
|
|
|
|
gfx::Size scale(double(aSize.width) / mSize.width,
|
|
|
|
double(aSize.height) / mSize.height);
|
2014-09-22 14:30:20 -07:00
|
|
|
gfxFloat minFactor = gfxPrefs::ImageHQDownscalingMinFactor() / 1000.0;
|
2014-09-19 14:53:29 -07:00
|
|
|
return (scale.width < minFactor || scale.height < minFactor);
|
|
|
|
#endif
|
2014-09-14 21:51:20 -07:00
|
|
|
}
|
2014-07-28 14:27:39 -07:00
|
|
|
|
2014-09-14 21:51:20 -07:00
|
|
|
void
|
2014-09-19 14:53:29 -07:00
|
|
|
RasterImage::NotifyNewScaledFrame()
|
2014-09-14 21:51:20 -07:00
|
|
|
{
|
2014-11-14 20:10:47 -08:00
|
|
|
if (mProgressTracker) {
|
2014-09-19 14:53:29 -07:00
|
|
|
// Send an invalidation so observers will repaint and can take advantage of
|
|
|
|
// the new scaled frame if possible.
|
2014-11-10 12:37:35 -08:00
|
|
|
nsIntRect rect(0, 0, mSize.width, mSize.height);
|
2014-11-14 20:10:47 -08:00
|
|
|
mProgressTracker->SyncNotifyProgress(NoProgress, rect);
|
2014-09-14 23:17:28 -07:00
|
|
|
}
|
2014-09-16 19:04:53 -07:00
|
|
|
}
|
2014-09-14 23:17:28 -07:00
|
|
|
|
2014-09-16 19:04:53 -07:00
|
|
|
void
|
2014-09-19 14:53:29 -07:00
|
|
|
RasterImage::RequestScale(imgFrame* aFrame,
|
|
|
|
uint32_t aFlags,
|
|
|
|
const nsIntSize& aSize)
|
2014-09-16 19:04:53 -07:00
|
|
|
{
|
2014-09-19 14:53:29 -07:00
|
|
|
// We don't scale frames which aren't fully decoded.
|
|
|
|
if (!aFrame->ImageComplete()) {
|
2014-09-16 22:30:11 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
// We can't scale frames that need padding or are single pixel.
|
|
|
|
if (aFrame->NeedsPadding() || aFrame->IsSinglePixel()) {
|
2014-09-18 19:26:01 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-16 22:30:11 -07:00
|
|
|
// We also can't scale if we can't lock the image data for this frame.
|
2014-09-12 01:12:55 -07:00
|
|
|
RawAccessFrameRef frameRef = aFrame->RawAccessRef();
|
|
|
|
if (!frameRef) {
|
2014-07-28 14:27:39 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
nsRefPtr<ScaleRunner> runner =
|
|
|
|
new ScaleRunner(this, DecodeFlags(aFlags), aSize, Move(frameRef));
|
|
|
|
if (runner->Init()) {
|
2014-07-28 14:27:39 -07:00
|
|
|
if (!sScaleWorkerThread) {
|
|
|
|
NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread));
|
|
|
|
ClearOnShutdown(&sScaleWorkerThread);
|
|
|
|
}
|
|
|
|
|
|
|
|
sScaleWorkerThread->Dispatch(runner, NS_DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
void
|
|
|
|
RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
|
2014-09-16 19:02:26 -07:00
|
|
|
gfxContext* aContext,
|
2014-08-22 13:12:38 -07:00
|
|
|
const nsIntSize& aSize,
|
|
|
|
const ImageRegion& aRegion,
|
2013-10-01 14:01:19 -07:00
|
|
|
GraphicsFilter aFilter,
|
2013-04-25 15:08:58 -07:00
|
|
|
uint32_t aFlags)
|
2012-04-03 14:57:22 -07:00
|
|
|
{
|
2014-09-12 18:29:27 -07:00
|
|
|
DrawableFrameRef frameRef;
|
2012-04-03 14:57:22 -07:00
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
if (CanScale(aFilter, aSize, aFlags)) {
|
|
|
|
frameRef =
|
|
|
|
SurfaceCache::Lookup(ImageKey(this),
|
|
|
|
RasterSurfaceKey(aSize.ToIntSize(),
|
|
|
|
DecodeFlags(aFlags)));
|
|
|
|
if (!frameRef) {
|
|
|
|
// We either didn't have a matching scaled frame or the OS threw it away.
|
|
|
|
// Request a new one so we'll be ready next time. For now, we'll fall back
|
|
|
|
// to aFrameRef below.
|
|
|
|
RequestScale(aFrameRef.get(), aFlags, aSize);
|
2012-10-10 08:35:23 -07:00
|
|
|
}
|
2014-09-19 14:53:29 -07:00
|
|
|
if (frameRef && !frameRef->ImageComplete()) {
|
|
|
|
frameRef.reset(); // We're still scaling, so we can't use this yet.
|
2012-04-03 14:57:22 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
|
2014-08-22 13:12:38 -07:00
|
|
|
ImageRegion region(aRegion);
|
2014-09-12 18:29:27 -07:00
|
|
|
if (!frameRef) {
|
|
|
|
frameRef = Move(aFrameRef);
|
|
|
|
}
|
2014-08-22 13:12:38 -07:00
|
|
|
|
|
|
|
// By now we may have a frame with the requested size. If not, we need to
|
|
|
|
// adjust the drawing parameters accordingly.
|
2014-09-12 18:29:27 -07:00
|
|
|
nsIntRect finalFrameRect = frameRef->GetRect();
|
|
|
|
if (finalFrameRect.Size() != aSize) {
|
2014-09-19 14:53:29 -07:00
|
|
|
gfx::Size scale(double(aSize.width) / mSize.width,
|
|
|
|
double(aSize.height) / mSize.height);
|
2014-08-22 13:12:38 -07:00
|
|
|
aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
|
|
|
|
region.Scale(1.0 / scale.width, 1.0 / scale.height);
|
|
|
|
}
|
|
|
|
|
2014-09-16 19:02:26 -07:00
|
|
|
// We can only use padding if we're using the original |aFrameRef|, unscaled.
|
|
|
|
// (If so, we moved it into |frameRef|, so |aFrameRef| is empty.) Because of
|
|
|
|
// this restriction, we don't scale frames that require padding.
|
|
|
|
nsIntMargin padding(0, 0, 0, 0);
|
|
|
|
if (!aFrameRef) {
|
|
|
|
padding = nsIntMargin(finalFrameRect.y,
|
|
|
|
mSize.width - finalFrameRect.XMost(),
|
|
|
|
mSize.height - finalFrameRect.YMost(),
|
|
|
|
finalFrameRect.x);
|
|
|
|
}
|
2012-04-03 14:57:22 -07:00
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
frameRef->Draw(aContext, region, padding, aFilter, aFlags);
|
2012-04-03 14:57:22 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
//******************************************************************************
|
2010-07-05 13:49:05 -07:00
|
|
|
/* [noscript] void draw(in gfxContext aContext,
|
|
|
|
* in gfxGraphicsFilter aFilter,
|
|
|
|
* [const] in gfxMatrix aUserSpaceToImageSpace,
|
|
|
|
* [const] in gfxRect aFill,
|
|
|
|
* [const] in nsIntRect aSubimage,
|
2010-09-08 13:40:39 -07:00
|
|
|
* [const] in nsIntSize aViewportSize,
|
2013-02-28 12:22:43 -08:00
|
|
|
* [const] in SVGImageContext aSVGContext,
|
2013-03-10 18:43:37 -07:00
|
|
|
* in uint32_t aWhichFrame,
|
2012-08-22 08:56:38 -07:00
|
|
|
* in uint32_t aFlags); */
|
2010-08-13 21:09:49 -07:00
|
|
|
NS_IMETHODIMP
|
2014-08-22 13:12:38 -07:00
|
|
|
RasterImage::Draw(gfxContext* aContext,
|
|
|
|
const nsIntSize& aSize,
|
|
|
|
const ImageRegion& aRegion,
|
2013-03-10 18:43:37 -07:00
|
|
|
uint32_t aWhichFrame,
|
2014-08-22 13:12:38 -07:00
|
|
|
GraphicsFilter aFilter,
|
|
|
|
const Maybe<SVGImageContext>& /*aSVGContext - ignored*/,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aFlags)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2013-03-10 18:43:37 -07:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE)
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2011-01-12 17:45:13 -08:00
|
|
|
// Illegal -- you can't draw with non-default decode flags.
|
|
|
|
// (Disabling colorspace conversion might make sense to allow, but
|
|
|
|
// we don't currently.)
|
|
|
|
if ((aFlags & DECODE_FLAGS_MASK) != DECODE_FLAGS_DEFAULT)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aContext);
|
|
|
|
|
2014-03-04 17:59:03 -08:00
|
|
|
// We can only draw without discarding and redecoding in these cases:
|
|
|
|
// * We have the default decode flags.
|
|
|
|
// * We have exactly FLAG_DECODE_NO_PREMULTIPLY_ALPHA and the current frame
|
|
|
|
// is opaque.
|
|
|
|
bool haveDefaultFlags = (mFrameDecodeFlags == DECODE_FLAGS_DEFAULT);
|
|
|
|
bool haveSafeAlphaFlags =
|
|
|
|
(mFrameDecodeFlags == FLAG_DECODE_NO_PREMULTIPLY_ALPHA) &&
|
|
|
|
FrameIsOpaque(FRAME_CURRENT);
|
|
|
|
|
|
|
|
if (!(haveDefaultFlags || haveSafeAlphaFlags)) {
|
2014-01-21 15:19:22 -08:00
|
|
|
if (!CanForciblyDiscardAndRedecode())
|
2011-01-12 17:45:13 -08:00
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
ForceDiscard();
|
|
|
|
|
|
|
|
mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
|
|
|
|
}
|
|
|
|
|
2012-03-08 06:14:00 -08:00
|
|
|
// If this image is a candidate for discarding, reset its position in the
|
|
|
|
// discard tracker so we're less likely to discard it right away.
|
|
|
|
//
|
|
|
|
// (We don't normally draw unlocked images, so this conditition will usually
|
|
|
|
// be false. But we will draw unlocked images if image locking is globally
|
2013-09-30 10:53:46 -07:00
|
|
|
// disabled via the image.mem.allow_locking_in_content_processes pref.)
|
2012-03-08 06:14:00 -08:00
|
|
|
if (DiscardingActive()) {
|
|
|
|
DiscardTracker::Reset(&mDiscardTrackerNode);
|
|
|
|
}
|
|
|
|
|
2013-04-26 12:58:17 -07:00
|
|
|
|
2014-11-14 20:10:47 -08:00
|
|
|
if (IsUnlocked() && mProgressTracker) {
|
|
|
|
mProgressTracker->OnUnlockedDraw();
|
2013-02-24 16:59:22 -08:00
|
|
|
}
|
|
|
|
|
2011-12-19 13:42:36 -08:00
|
|
|
// We use !mDecoded && mHasSourceData to mean discarded.
|
|
|
|
if (!mDecoded && mHasSourceData) {
|
2013-03-01 15:17:24 -08:00
|
|
|
mDrawStartTime = TimeStamp::Now();
|
2011-08-10 16:12:08 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// If a synchronous draw is requested, flush anything that might be sitting around
|
|
|
|
if (aFlags & FLAG_SYNC_DECODE) {
|
|
|
|
nsresult rv = SyncDecode();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2014-09-26 18:50:24 -07:00
|
|
|
DrawableFrameRef ref = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
|
|
|
|
aFlags);
|
2014-09-12 18:29:27 -07:00
|
|
|
if (!ref) {
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_OK; // Getting the frame (above) touches the image and kicks off decoding
|
|
|
|
}
|
|
|
|
|
2014-09-12 18:29:27 -07:00
|
|
|
DrawWithPreDownscaleIfNeeded(Move(ref), aContext, aSize, aRegion, aFilter, aFlags);
|
2014-02-24 19:37:51 -08:00
|
|
|
|
2011-08-10 16:12:08 -07:00
|
|
|
if (mDecoded && !mDrawStartTime.IsNull()) {
|
|
|
|
TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
|
2012-08-22 08:56:38 -07:00
|
|
|
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds()));
|
2011-08-10 16:12:08 -07:00
|
|
|
// clear the value of mDrawStartTime
|
|
|
|
mDrawStartTime = TimeStamp();
|
|
|
|
}
|
2012-04-03 14:57:22 -07:00
|
|
|
|
2007-10-18 17:36:34 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* void lockImage() */
|
2007-10-18 17:36:34 -07:00
|
|
|
NS_IMETHODIMP
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::LockImage()
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2013-09-28 11:28:43 -07:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(),
|
|
|
|
"Main thread to encourage serialization with UnlockImage");
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Cancel the discard timer if it's there
|
2010-08-13 21:09:49 -07:00
|
|
|
DiscardTracker::Remove(&mDiscardTrackerNode);
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
// Increment the lock count
|
|
|
|
mLockCount++;
|
|
|
|
|
2007-10-18 17:36:34 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* void unlockImage() */
|
2007-10-18 17:36:34 -07:00
|
|
|
NS_IMETHODIMP
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::UnlockImage()
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2013-09-28 11:28:43 -07:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(),
|
|
|
|
"Main thread to encourage serialization with LockImage");
|
2009-09-12 15:44:18 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// It's an error to call this function if the lock count is 0
|
|
|
|
NS_ABORT_IF_FALSE(mLockCount > 0,
|
|
|
|
"Calling UnlockImage with mLockCount == 0!");
|
|
|
|
if (mLockCount == 0)
|
|
|
|
return NS_ERROR_ABORT;
|
|
|
|
|
2010-07-01 10:39:44 -07:00
|
|
|
// We're locked, so discarding should not be active
|
|
|
|
NS_ABORT_IF_FALSE(!DiscardingActive(), "Locked, but discarding activated");
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
// Decrement our lock count
|
|
|
|
mLockCount--;
|
|
|
|
|
2011-07-21 11:15:17 -07:00
|
|
|
// If we've decoded this image once before, we're currently decoding again,
|
|
|
|
// and our lock count is now zero (so nothing is forcing us to keep the
|
|
|
|
// decoded data around), try to cancel the decode and throw away whatever
|
|
|
|
// we've decoded.
|
|
|
|
if (mHasBeenDecoded && mDecoder &&
|
|
|
|
mLockCount == 0 && CanForciblyDiscard()) {
|
2012-10-29 16:32:10 -07:00
|
|
|
PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
2011-07-21 11:15:17 -07:00
|
|
|
("RasterImage[0x%p] canceling decode because image "
|
|
|
|
"is now unlocked.", this));
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
2013-01-28 09:26:36 -08:00
|
|
|
FinishedSomeDecoding(eShutdownIntent_NotNeeded);
|
2011-07-21 11:15:17 -07:00
|
|
|
ForceDiscard();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we might still be a candidate for discarding in the future. If
|
|
|
|
// we are, add ourselves to the discard tracker.
|
2009-09-12 15:44:18 -07:00
|
|
|
if (CanDiscard()) {
|
2010-08-13 21:09:49 -07:00
|
|
|
nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
2009-09-12 15:44:18 -07:00
|
|
|
CONTAINER_ENSURE_SUCCESS(rv);
|
|
|
|
}
|
|
|
|
|
2007-10-18 17:36:34 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-09 22:29:28 -08:00
|
|
|
//******************************************************************************
|
|
|
|
/* void requestDiscard() */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::RequestDiscard()
|
|
|
|
{
|
2014-01-21 15:19:22 -08:00
|
|
|
if (CanDiscard() && CanForciblyDiscardAndRedecode()) {
|
2012-03-09 22:29:28 -08:00
|
|
|
ForceDiscard();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// Flushes up to aMaxBytes to the decoder.
|
|
|
|
nsresult
|
2014-05-08 18:03:35 -07:00
|
|
|
RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy)
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2014-10-15 13:52:20 -07:00
|
|
|
MOZ_ASSERT(mDecoder, "Should have a decoder");
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-12-17 14:04:31 -08:00
|
|
|
mDecodingMonitor.AssertCurrentThreadIn();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// First, if we've just been called because we allocated a frame on the main
|
|
|
|
// thread, let the decoder deal with the data it set aside at that time by
|
|
|
|
// passing it a null buffer.
|
2014-11-18 12:06:27 -08:00
|
|
|
if (mDecoder->NeedsToFlushData()) {
|
2013-12-17 14:04:24 -08:00
|
|
|
nsresult rv = WriteToDecoder(nullptr, 0, aStrategy);
|
2013-02-27 11:23:08 -08:00
|
|
|
if (NS_FAILED(rv) || mDecoder->NeedsNewFrame()) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-15 13:52:20 -07:00
|
|
|
// If we have nothing else to decode, return.
|
|
|
|
if (mDecoder->BytesDecoded() == mSourceData.Length()) {
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_OK;
|
2014-10-15 13:52:20 -07:00
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2014-10-15 13:52:20 -07:00
|
|
|
MOZ_ASSERT(mDecoder->BytesDecoded() < mSourceData.Length());
|
2013-05-21 22:38:06 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// write the proper amount of data
|
2014-10-15 13:52:20 -07:00
|
|
|
size_t bytesToDecode = min(aMaxBytes,
|
|
|
|
mSourceData.Length() - mDecoder->BytesDecoded());
|
|
|
|
return WriteToDecoder(mSourceData.Elements() + mDecoder->BytesDecoded(),
|
|
|
|
bytesToDecode,
|
|
|
|
aStrategy);
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// There are various indicators that tell us we're finished with the decode
|
|
|
|
// task at hand and can shut down the decoder.
|
2010-08-22 19:30:46 -07:00
|
|
|
//
|
|
|
|
// This method may not be called if there is no decoder.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-08-13 21:09:49 -07:00
|
|
|
RasterImage::IsDecodeFinished()
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2010-08-22 19:30:46 -07:00
|
|
|
// Precondition
|
2013-12-17 14:04:31 -08:00
|
|
|
mDecodingMonitor.AssertCurrentThreadIn();
|
2014-10-15 13:52:20 -07:00
|
|
|
MOZ_ASSERT(mDecoder, "Should have a decoder");
|
2010-08-22 19:30:46 -07:00
|
|
|
|
2013-04-03 16:34:56 -07:00
|
|
|
// The decode is complete if we got what we wanted.
|
2010-08-22 19:30:46 -07:00
|
|
|
if (mDecoder->IsSizeDecode()) {
|
2013-04-03 16:34:56 -07:00
|
|
|
if (mDecoder->HasSize()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (mDecoder->GetDecodeDone()) {
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-15 14:34:18 -07:00
|
|
|
|
2013-04-03 16:34:56 -07:00
|
|
|
// If the decoder returned because it needed a new frame and we haven't
|
|
|
|
// written to it since then, the decoder may be storing data that it hasn't
|
|
|
|
// decoded yet.
|
2014-11-18 12:06:27 -08:00
|
|
|
if (mDecoder->NeedsNewFrame() || mDecoder->NeedsToFlushData()) {
|
2013-04-03 16:34:56 -07:00
|
|
|
return false;
|
2009-09-12 15:44:18 -07:00
|
|
|
}
|
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// Otherwise, if we have all the source data and wrote all the source data,
|
|
|
|
// we're done.
|
2009-09-12 15:44:18 -07:00
|
|
|
//
|
2013-04-03 16:34:56 -07:00
|
|
|
// (NB - This can be the case even for non-erroneous images because
|
|
|
|
// Decoder::GetDecodeDone() might not return true until after we call
|
|
|
|
// Decoder::Finish() in ShutdownDecoder())
|
2014-10-15 13:52:20 -07:00
|
|
|
if (mHasSourceData && (mDecoder->BytesDecoded() == mSourceData.Length())) {
|
2013-04-03 16:34:56 -07:00
|
|
|
return true;
|
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-04-03 16:34:56 -07:00
|
|
|
// If we get here, assume it's not finished.
|
|
|
|
return false;
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// Indempotent error flagging routine. If a decoder is open, shuts it down.
|
2010-08-13 21:09:49 -07:00
|
|
|
void
|
|
|
|
RasterImage::DoError()
|
2007-10-18 17:36:34 -07:00
|
|
|
{
|
2009-09-12 15:44:18 -07:00
|
|
|
// If we've flagged an error before, we have nothing to do
|
|
|
|
if (mError)
|
|
|
|
return;
|
|
|
|
|
2013-09-12 14:40:16 -07:00
|
|
|
// We can't safely handle errors off-main-thread, so dispatch a worker to do it.
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
HandleErrorWorker::DispatchIfNeeded(this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-14 20:06:19 -08:00
|
|
|
// Calling FinishedSomeDecoding requires us to be in the decoding monitor.
|
2013-12-17 14:04:32 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
|
|
|
|
2010-09-12 08:22:30 -07:00
|
|
|
// If we're mid-decode, shut down the decoder.
|
2013-01-18 13:47:18 -08:00
|
|
|
if (mDecoder) {
|
2013-01-28 09:26:36 -08:00
|
|
|
FinishedSomeDecoding(eShutdownIntent_Error);
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
2009-09-12 15:44:18 -07:00
|
|
|
|
2013-09-12 14:40:16 -07:00
|
|
|
// Put the container in an error state.
|
2011-10-17 07:59:28 -07:00
|
|
|
mError = true;
|
2009-09-12 15:44:18 -07:00
|
|
|
|
|
|
|
// Log our error
|
|
|
|
LOG_CONTAINER_ERROR;
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
|
|
|
|
2013-09-12 14:40:16 -07:00
|
|
|
/* static */ void
|
|
|
|
RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
|
|
|
|
{
|
|
|
|
if (!aImage->mPendingError) {
|
|
|
|
aImage->mPendingError = true;
|
|
|
|
nsRefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);
|
|
|
|
NS_DispatchToMainThread(worker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RasterImage::HandleErrorWorker::HandleErrorWorker(RasterImage* aImage)
|
|
|
|
: mImage(aImage)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mImage, "Should have image");
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::HandleErrorWorker::Run()
|
|
|
|
{
|
|
|
|
mImage->DoError();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
// nsIInputStream callback to copy the incoming image data directly to the
|
2010-08-13 21:09:51 -07:00
|
|
|
// RasterImage without processing. The RasterImage is passed as the closure.
|
2009-09-12 15:44:18 -07:00
|
|
|
// Always reads everything it gets, even if the data is erroneous.
|
|
|
|
NS_METHOD
|
2010-08-13 21:09:51 -07:00
|
|
|
RasterImage::WriteToRasterImage(nsIInputStream* /* unused */,
|
|
|
|
void* aClosure,
|
|
|
|
const char* aFromRawSegment,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t /* unused */,
|
|
|
|
uint32_t aCount,
|
|
|
|
uint32_t* aWriteCount)
|
2009-09-12 15:44:18 -07:00
|
|
|
{
|
2010-08-13 21:09:49 -07:00
|
|
|
// Retrieve the RasterImage
|
2010-08-13 21:09:51 -07:00
|
|
|
RasterImage* image = static_cast<RasterImage*>(aClosure);
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2011-06-08 19:21:53 -07:00
|
|
|
// Copy the source data. Unless we hit OOM, we squelch the return value
|
|
|
|
// here, because returning an error means that ReadSegments stops
|
|
|
|
// reading data, violating our invariant that we read everything we get.
|
|
|
|
// If we hit OOM then we fail and the load is aborted.
|
|
|
|
nsresult rv = image->AddSourceData(aFromRawSegment, aCount);
|
|
|
|
if (rv == NS_ERROR_OUT_OF_MEMORY) {
|
|
|
|
image->DoError();
|
|
|
|
return rv;
|
|
|
|
}
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
// We wrote everything we got
|
2010-08-13 21:09:51 -07:00
|
|
|
*aWriteCount = aCount;
|
2007-10-18 17:36:34 -07:00
|
|
|
|
2009-09-12 15:44:18 -07:00
|
|
|
return NS_OK;
|
2007-10-18 17:36:34 -07:00
|
|
|
}
|
2010-08-13 21:09:49 -07:00
|
|
|
|
2011-08-05 06:57:16 -07:00
|
|
|
bool
|
2010-09-07 17:33:02 -07:00
|
|
|
RasterImage::ShouldAnimate()
|
|
|
|
{
|
2013-06-17 13:49:04 -07:00
|
|
|
return ImageResource::ShouldAnimate() && GetNumFrames() >= 2 &&
|
2010-11-17 12:39:23 -08:00
|
|
|
!mAnimationFinished;
|
2010-09-07 17:33:02 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
/* readonly attribute uint32_t framesNotified; */
|
2010-09-07 17:34:18 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
RasterImage::GetFramesNotified(uint32_t *aFramesNotified)
|
2010-09-07 17:34:18 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aFramesNotified);
|
|
|
|
|
|
|
|
*aFramesNotified = mFramesNotified;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-11-26 17:22:44 -08:00
|
|
|
nsresult
|
|
|
|
RasterImage::RequestDecodeIfNeeded(nsresult aStatus,
|
|
|
|
eShutdownIntent aIntent,
|
|
|
|
bool aDone,
|
|
|
|
bool aWasSize)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// If we were a size decode and a full decode was requested, now's the time.
|
|
|
|
if (NS_SUCCEEDED(aStatus) &&
|
2014-01-17 21:14:46 -08:00
|
|
|
aIntent == eShutdownIntent_Done &&
|
2013-11-26 17:22:44 -08:00
|
|
|
aDone &&
|
|
|
|
aWasSize &&
|
|
|
|
mWantFullDecode) {
|
|
|
|
mWantFullDecode = false;
|
|
|
|
|
|
|
|
// If we're not meant to be storing source data and we just got the size,
|
|
|
|
// we need to synchronously flush all the data we got to a full decoder.
|
|
|
|
// When that decoder is shut down, we'll also clear our source data.
|
|
|
|
return StoringSourceData() ? RequestDecode()
|
|
|
|
: SyncDecode();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't need a full decode right now, so just return the existing status.
|
|
|
|
return aStatus;
|
|
|
|
}
|
|
|
|
|
2013-02-01 17:06:34 -08:00
|
|
|
nsresult
|
2013-01-28 09:26:36 -08:00
|
|
|
RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_Done */,
|
2014-11-14 20:06:19 -08:00
|
|
|
DecodeRequest* aRequest /* = nullptr */,
|
2014-11-14 20:10:47 -08:00
|
|
|
Progress aProgress /* = NoProgress */)
|
2013-01-18 13:47:18 -08:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2013-12-17 14:04:31 -08:00
|
|
|
mDecodingMonitor.AssertCurrentThreadIn();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
nsRefPtr<DecodeRequest> request;
|
|
|
|
if (aRequest) {
|
|
|
|
request = aRequest;
|
|
|
|
} else {
|
|
|
|
request = mDecodeRequest;
|
|
|
|
}
|
2013-01-18 13:47:18 -08:00
|
|
|
|
|
|
|
// Ensure that, if the decoder is the last reference to the image, we don't
|
|
|
|
// destroy it by destroying the decoder.
|
2013-01-28 09:26:36 -08:00
|
|
|
nsRefPtr<RasterImage> image(this);
|
2013-01-18 13:47:18 -08:00
|
|
|
|
|
|
|
bool done = false;
|
2013-01-31 10:38:24 -08:00
|
|
|
bool wasSize = false;
|
2014-11-10 12:37:35 -08:00
|
|
|
nsIntRect invalidRect;
|
2013-02-01 17:06:34 -08:00
|
|
|
nsresult rv = NS_OK;
|
2014-11-14 20:10:47 -08:00
|
|
|
Progress progress = aProgress;
|
2013-01-18 13:47:18 -08:00
|
|
|
|
|
|
|
if (image->mDecoder) {
|
2014-11-10 12:37:35 -08:00
|
|
|
invalidRect = image->mDecoder->TakeInvalidRect();
|
2014-11-18 01:48:49 -08:00
|
|
|
progress |= image->mDecoder->TakeProgress();
|
2014-11-10 12:37:35 -08:00
|
|
|
|
2014-11-18 12:06:26 -08:00
|
|
|
if (!image->mDecoder->IsSizeDecode() && image->mDecoder->ChunkCount()) {
|
|
|
|
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS,
|
|
|
|
image->mDecoder->ChunkCount());
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
if (!image->mHasSize && image->mDecoder->HasSize()) {
|
|
|
|
image->mDecoder->SetSizeOnImage();
|
|
|
|
}
|
|
|
|
|
2013-01-28 09:26:36 -08:00
|
|
|
// If the decode finished, or we're specifically being told to shut down,
|
|
|
|
// tell the image and shut down the decoder.
|
2013-04-03 16:34:56 -07:00
|
|
|
if (image->IsDecodeFinished() || aIntent != eShutdownIntent_Done) {
|
2013-01-18 13:47:18 -08:00
|
|
|
done = true;
|
|
|
|
|
|
|
|
// Hold on to a reference to the decoder until we're done with it
|
|
|
|
nsRefPtr<Decoder> decoder = image->mDecoder;
|
|
|
|
|
2013-01-31 10:38:24 -08:00
|
|
|
wasSize = decoder->IsSizeDecode();
|
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
// Do some telemetry if this isn't a size decode.
|
2014-10-15 16:00:12 -07:00
|
|
|
if (request && !wasSize) {
|
2013-01-18 13:47:18 -08:00
|
|
|
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
|
2014-11-18 12:06:26 -08:00
|
|
|
int32_t(decoder->DecodeTime().ToMicroseconds()));
|
2013-01-18 13:47:18 -08:00
|
|
|
|
|
|
|
// We record the speed for only some decoders. The rest have
|
|
|
|
// SpeedHistogram return HistogramCount.
|
|
|
|
Telemetry::ID id = decoder->SpeedHistogram();
|
|
|
|
if (id < Telemetry::HistogramCount) {
|
2014-10-15 13:52:20 -07:00
|
|
|
int32_t KBps = int32_t(decoder->BytesDecoded() /
|
2014-11-18 12:06:26 -08:00
|
|
|
(1024 * decoder->DecodeTime().ToSeconds()));
|
2013-01-18 13:47:18 -08:00
|
|
|
Telemetry::Accumulate(id, KBps);
|
|
|
|
}
|
|
|
|
}
|
2013-05-30 07:32:16 -07:00
|
|
|
|
|
|
|
// We need to shut down the decoder first, in order to ensure all
|
|
|
|
// decoding routines have been finished.
|
|
|
|
rv = image->ShutdownDecoder(aIntent);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
image->DoError();
|
|
|
|
}
|
2014-11-14 20:06:19 -08:00
|
|
|
|
2014-11-18 01:48:49 -08:00
|
|
|
// If there were any final changes, grab them.
|
|
|
|
invalidRect.Union(decoder->TakeInvalidRect());
|
2014-11-18 01:48:49 -08:00
|
|
|
progress |= decoder->TakeProgress();
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-10 12:37:35 -08:00
|
|
|
if (GetCurrentFrameIndex() > 0) {
|
|
|
|
// Don't send invalidations for animated frames after the first; let
|
|
|
|
// RequestRefresh take care of that.
|
|
|
|
invalidRect = nsIntRect();
|
|
|
|
}
|
|
|
|
if (mHasBeenDecoded && !invalidRect.IsEmpty()) {
|
|
|
|
// Don't send partial invalidations if we've been decoded before.
|
|
|
|
invalidRect = mDecoded ? GetFirstFrameRect()
|
|
|
|
: nsIntRect();
|
|
|
|
}
|
|
|
|
|
2013-11-26 17:22:44 -08:00
|
|
|
if (mNotifying) {
|
2014-11-14 20:10:47 -08:00
|
|
|
// Accumulate the progress changes. We don't permit recursive notifications
|
2013-11-26 17:22:44 -08:00
|
|
|
// because they cause subtle concurrency bugs, so we'll delay sending out
|
|
|
|
// the notifications until we pop back to the lowest invocation of
|
|
|
|
// FinishedSomeDecoding on the stack.
|
2014-11-14 20:10:47 -08:00
|
|
|
mNotifyProgress |= progress;
|
|
|
|
mNotifyInvalidRect.Union(invalidRect);
|
2013-11-26 17:22:44 -08:00
|
|
|
} else {
|
2014-11-14 20:10:47 -08:00
|
|
|
MOZ_ASSERT(mNotifyProgress == NoProgress && mNotifyInvalidRect.IsEmpty(),
|
|
|
|
"Shouldn't have an accumulated change at this point");
|
2013-11-26 17:22:44 -08:00
|
|
|
|
2014-11-14 20:10:47 -08:00
|
|
|
progress = image->mProgressTracker->Difference(progress);
|
2014-11-14 20:10:47 -08:00
|
|
|
|
2014-11-14 20:10:47 -08:00
|
|
|
while (progress != NoProgress || !invalidRect.IsEmpty()) {
|
2013-11-26 17:22:44 -08:00
|
|
|
// Tell the observers what happened.
|
|
|
|
mNotifying = true;
|
2014-11-14 20:10:47 -08:00
|
|
|
image->mProgressTracker->SyncNotifyProgress(progress, invalidRect);
|
2013-11-26 17:22:44 -08:00
|
|
|
mNotifying = false;
|
|
|
|
|
2014-11-14 20:10:47 -08:00
|
|
|
// Gather any progress changes that may have occurred as a result of sending
|
2013-11-26 17:22:44 -08:00
|
|
|
// out the previous notifications. If there were any, we'll send out
|
|
|
|
// notifications for them next.
|
2014-11-14 20:10:47 -08:00
|
|
|
progress = image->mProgressTracker->Difference(mNotifyProgress);
|
|
|
|
mNotifyProgress = NoProgress;
|
|
|
|
|
|
|
|
invalidRect = mNotifyInvalidRect;
|
|
|
|
mNotifyInvalidRect = nsIntRect();
|
2013-11-26 17:22:44 -08:00
|
|
|
}
|
2013-01-31 10:38:24 -08:00
|
|
|
}
|
2013-02-01 17:06:34 -08:00
|
|
|
|
2013-11-26 17:22:44 -08:00
|
|
|
return RequestDecodeIfNeeded(rv, aIntent, done, wasSize);
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
|
|
|
|
2014-06-27 20:50:26 -07:00
|
|
|
already_AddRefed<imgIContainer>
|
|
|
|
RasterImage::Unwrap()
|
|
|
|
{
|
|
|
|
nsCOMPtr<imgIContainer> self(this);
|
|
|
|
return self.forget();
|
|
|
|
}
|
|
|
|
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(RasterImage::DecodePool,
|
|
|
|
nsIObserver)
|
2013-03-01 15:17:24 -08:00
|
|
|
|
|
|
|
/* static */ RasterImage::DecodePool*
|
|
|
|
RasterImage::DecodePool::Singleton()
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
|
|
|
if (!sSingleton) {
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
sSingleton = new DecodePool();
|
2012-02-09 12:04:30 -08:00
|
|
|
ClearOnShutdown(&sSingleton);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sSingleton;
|
|
|
|
}
|
|
|
|
|
2013-09-28 11:28:42 -07:00
|
|
|
already_AddRefed<nsIEventTarget>
|
|
|
|
RasterImage::DecodePool::GetEventTarget()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
|
|
|
|
return target.forget();
|
|
|
|
}
|
|
|
|
|
2013-06-03 03:14:42 -07:00
|
|
|
#ifdef MOZ_NUWA_PROCESS
|
|
|
|
|
2014-07-30 19:29:52 -07:00
|
|
|
class RIDThreadPoolListener MOZ_FINAL : public nsIThreadPoolListener
|
2013-06-03 03:14:42 -07:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
NS_DECL_NSITHREADPOOLLISTENER
|
|
|
|
|
|
|
|
RIDThreadPoolListener() {}
|
|
|
|
~RIDThreadPoolListener() {}
|
|
|
|
};
|
|
|
|
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(RIDThreadPoolListener, nsIThreadPoolListener)
|
2013-06-03 03:14:42 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RIDThreadPoolListener::OnThreadCreated()
|
|
|
|
{
|
|
|
|
if (IsNuwaProcess()) {
|
|
|
|
NuwaMarkCurrentThread((void (*)(void *))nullptr, nullptr);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RIDThreadPoolListener::OnThreadShuttingDown()
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // MOZ_NUWA_PROCESS
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
RasterImage::DecodePool::DecodePool()
|
2013-04-17 17:05:19 -07:00
|
|
|
: mThreadPoolMutex("Thread Pool")
|
2013-01-18 13:47:18 -08:00
|
|
|
{
|
2014-09-22 14:30:20 -07:00
|
|
|
if (gfxPrefs::ImageMTDecodingEnabled()) {
|
2013-03-01 15:42:08 -08:00
|
|
|
mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
|
|
|
|
if (mThreadPool) {
|
|
|
|
mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
|
2014-09-22 14:30:20 -07:00
|
|
|
int32_t prefLimit = gfxPrefs::ImageMTDecodingLimit();
|
2013-04-23 07:06:56 -07:00
|
|
|
uint32_t limit;
|
2014-09-22 14:30:20 -07:00
|
|
|
if (prefLimit <= 0) {
|
2013-04-23 07:06:56 -07:00
|
|
|
limit = std::max(PR_GetNumberOfProcessors(), 2) - 1;
|
2013-03-01 15:42:08 -08:00
|
|
|
} else {
|
2014-09-22 14:30:20 -07:00
|
|
|
limit = static_cast<uint32_t>(prefLimit);
|
2013-03-01 15:42:08 -08:00
|
|
|
}
|
2013-03-24 12:43:20 -07:00
|
|
|
|
2013-04-23 07:06:56 -07:00
|
|
|
mThreadPool->SetThreadLimit(limit);
|
|
|
|
mThreadPool->SetIdleThreadLimit(limit);
|
|
|
|
|
2013-06-03 03:14:42 -07:00
|
|
|
#ifdef MOZ_NUWA_PROCESS
|
|
|
|
if (IsNuwaProcess()) {
|
|
|
|
mThreadPool->SetListener(new RIDThreadPoolListener());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-06-16 15:25:43 -07:00
|
|
|
nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
|
2013-03-01 15:42:08 -08:00
|
|
|
if (obsSvc) {
|
|
|
|
obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
|
|
|
|
}
|
2013-03-01 15:17:24 -08:00
|
|
|
}
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
RasterImage::DecodePool::~DecodePool()
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
|
2012-02-09 12:04:30 -08:00
|
|
|
}
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::DecodePool::Observe(nsISupports *subject, const char *topic,
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t *data)
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "oops");
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2013-04-04 18:01:41 -07:00
|
|
|
nsCOMPtr<nsIThreadPool> threadPool;
|
|
|
|
|
|
|
|
{
|
|
|
|
MutexAutoLock threadPoolLock(mThreadPoolMutex);
|
|
|
|
threadPool = mThreadPool;
|
2013-03-01 15:17:24 -08:00
|
|
|
mThreadPool = nullptr;
|
2013-04-04 18:01:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (threadPool) {
|
|
|
|
threadPool->Shutdown();
|
2013-03-24 12:43:20 -07:00
|
|
|
}
|
2013-03-01 15:17:24 -08:00
|
|
|
|
|
|
|
return NS_OK;
|
2012-02-09 12:04:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-01 15:17:24 -08:00
|
|
|
RasterImage::DecodePool::RequestDecode(RasterImage* aImg)
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
2013-01-18 13:47:18 -08:00
|
|
|
MOZ_ASSERT(aImg->mDecoder);
|
2013-12-17 14:04:31 -08:00
|
|
|
aImg->mDecodingMonitor.AssertCurrentThreadIn();
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// If we're currently waiting on a new frame for this image, we can't do any
|
|
|
|
// decoding.
|
|
|
|
if (!aImg->mDecoder->NeedsNewFrame()) {
|
2014-10-15 16:00:12 -07:00
|
|
|
if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING ||
|
|
|
|
aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) {
|
2013-03-01 15:17:24 -08:00
|
|
|
// The image is already in our list of images to decode, or currently being
|
|
|
|
// decoded, so we don't have to do anything else.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_PENDING;
|
|
|
|
nsRefPtr<DecodeJob> job = new DecodeJob(aImg->mDecodeRequest, aImg);
|
2013-04-17 17:05:19 -07:00
|
|
|
|
2013-04-04 18:01:41 -07:00
|
|
|
MutexAutoLock threadPoolLock(mThreadPoolMutex);
|
2014-09-22 14:30:20 -07:00
|
|
|
if (!gfxPrefs::ImageMTDecodingEnabled() || !mThreadPool) {
|
2013-03-01 15:17:24 -08:00
|
|
|
NS_DispatchToMainThread(job);
|
|
|
|
} else {
|
|
|
|
mThreadPool->Dispatch(job, nsIEventTarget::DISPATCH_NORMAL);
|
|
|
|
}
|
2013-02-27 11:23:08 -08:00
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
}
|
|
|
|
|
2012-08-13 11:12:15 -07:00
|
|
|
void
|
2013-12-17 14:04:24 -08:00
|
|
|
RasterImage::DecodePool::DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrategy)
|
2012-08-13 11:12:15 -07:00
|
|
|
{
|
2013-01-18 13:47:18 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-12-17 14:04:31 -08:00
|
|
|
aImg->mDecodingMonitor.AssertCurrentThreadIn();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
if (aImg->mDecodeRequest) {
|
|
|
|
// If the image is waiting for decode work to be notified, go ahead and do that.
|
|
|
|
if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
|
|
|
|
aImg->FinishedSomeDecoding();
|
|
|
|
}
|
2013-03-01 15:17:24 -08:00
|
|
|
}
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2013-12-17 14:04:24 -08:00
|
|
|
DecodeSomeOfImage(aImg, aStrategy);
|
2013-02-27 11:23:08 -08:00
|
|
|
|
2013-01-28 09:26:36 -08:00
|
|
|
aImg->FinishedSomeDecoding();
|
2012-08-24 11:24:36 -07:00
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// If the decoder needs a new frame, enqueue an event to get it; that event
|
|
|
|
// will enqueue another decode request when it's done.
|
|
|
|
if (aImg->mDecoder && aImg->mDecoder->NeedsNewFrame()) {
|
|
|
|
FrameNeededWorker::GetNewFrame(aImg);
|
|
|
|
} else {
|
|
|
|
// If we aren't yet finished decoding and we have more data in hand, add
|
|
|
|
// this request to the back of the priority list.
|
|
|
|
if (aImg->mDecoder &&
|
|
|
|
!aImg->mError &&
|
|
|
|
!aImg->IsDecodeFinished() &&
|
2014-10-15 13:52:20 -07:00
|
|
|
aImg->mSourceData.Length() > aImg->mDecoder->BytesDecoded()) {
|
2013-02-27 11:23:08 -08:00
|
|
|
RequestDecode(aImg);
|
|
|
|
}
|
2012-08-24 11:24:36 -07:00
|
|
|
}
|
2012-08-13 11:12:15 -07:00
|
|
|
}
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
/* static */ void
|
|
|
|
RasterImage::DecodePool::StopDecoding(RasterImage* aImg)
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
aImg->mDecodingMonitor.AssertCurrentThreadIn();
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
// If we haven't got a decode request, we're not currently decoding. (Having
|
|
|
|
// a decode request doesn't imply we *are* decoding, though.)
|
2014-10-15 16:00:12 -07:00
|
|
|
if (aImg->mDecodeRequest) {
|
|
|
|
aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_STOPPED;
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-01 15:17:24 -08:00
|
|
|
RasterImage::DecodePool::DecodeJob::Run()
|
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
|
2013-02-27 11:23:08 -08:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
// If we were interrupted, we shouldn't do any work.
|
2014-10-15 16:00:12 -07:00
|
|
|
if (mRequest->mRequestStatus == DecodeRequest::REQUEST_STOPPED) {
|
|
|
|
DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
|
2013-03-01 15:17:24 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
// If someone came along and synchronously decoded us, there's nothing for us to do.
|
2013-04-03 16:34:56 -07:00
|
|
|
if (!mImage->mDecoder || mImage->IsDecodeFinished()) {
|
2014-10-15 16:00:12 -07:00
|
|
|
DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
|
2013-03-01 15:17:24 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
// If we're a decode job that's been enqueued since a previous decode that
|
|
|
|
// still needs a new frame, we can't do anything. Wait until the
|
|
|
|
// FrameNeededWorker enqueues another frame.
|
|
|
|
if (mImage->mDecoder->NeedsNewFrame()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
mRequest->mRequestStatus = DecodeRequest::REQUEST_ACTIVE;
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 13:52:20 -07:00
|
|
|
size_t oldByteCount = mImage->mDecoder->BytesDecoded();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodeType type = DECODE_TYPE_UNTIL_DONE_BYTES;
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
// Multithreaded decoding can be disabled. If we've done so, we don't want to
|
|
|
|
// monopolize the main thread, and will allow a timeout in DecodeSomeOfImage.
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
type = DECODE_TYPE_UNTIL_TIME;
|
2013-03-01 15:17:24 -08:00
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2014-11-18 12:06:27 -08:00
|
|
|
size_t maxBytes = mImage->mSourceData.Length() -
|
|
|
|
mImage->mDecoder->BytesDecoded();
|
|
|
|
DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC,
|
|
|
|
type, maxBytes);
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 13:52:20 -07:00
|
|
|
size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount;
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
mRequest->mRequestStatus = DecodeRequest::REQUEST_WORK_DONE;
|
2013-03-01 15:17:24 -08:00
|
|
|
|
|
|
|
// If the decoder needs a new frame, enqueue an event to get it; that event
|
|
|
|
// will enqueue another decode request when it's done.
|
|
|
|
if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
|
|
|
|
FrameNeededWorker::GetNewFrame(mImage);
|
|
|
|
}
|
|
|
|
// If we aren't yet finished decoding and we have more data in hand, add
|
|
|
|
// this request to the back of the list.
|
|
|
|
else if (mImage->mDecoder &&
|
|
|
|
!mImage->mError &&
|
2013-09-12 14:40:16 -07:00
|
|
|
!mImage->mPendingError &&
|
2013-03-01 15:17:24 -08:00
|
|
|
!mImage->IsDecodeFinished() &&
|
2014-11-18 12:06:27 -08:00
|
|
|
bytesDecoded < maxBytes &&
|
2013-04-04 17:57:40 -07:00
|
|
|
bytesDecoded > 0) {
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodePool::Singleton()->RequestDecode(mImage);
|
|
|
|
} else {
|
|
|
|
// Nothing more for us to do - let everyone know what happened.
|
2014-10-15 16:00:12 -07:00
|
|
|
DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
|
2013-03-01 15:17:24 -08:00
|
|
|
}
|
2013-03-24 12:43:20 -07:00
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-06-16 19:05:00 -07:00
|
|
|
RasterImage::DecodePool::DecodeJob::~DecodeJob()
|
|
|
|
{
|
2014-09-22 14:30:20 -07:00
|
|
|
if (gfxPrefs::ImageMTDecodingEnabled()) {
|
2014-06-16 19:05:00 -07:00
|
|
|
// Dispatch mImage to main thread to prevent mImage from being destructed by decode thread.
|
|
|
|
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
|
|
|
NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
|
|
|
|
if (mainThread) {
|
|
|
|
// Handle ambiguous nsISupports inheritance
|
|
|
|
RasterImage* rawImg = nullptr;
|
|
|
|
mImage.swap(rawImg);
|
|
|
|
DebugOnly<nsresult> rv = NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
nsresult
|
2013-03-01 15:17:24 -08:00
|
|
|
RasterImage::DecodePool::DecodeUntilSizeAvailable(RasterImage* aImg)
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
2013-01-18 13:47:18 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(aImg->mDecodingMonitor);
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
if (aImg->mDecodeRequest) {
|
|
|
|
// If the image is waiting for decode work to be notified, go ahead and do that.
|
|
|
|
if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
|
|
|
|
nsresult rv = aImg->FinishedSomeDecoding();
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aImg->DoError();
|
|
|
|
return rv;
|
|
|
|
}
|
2013-03-01 15:17:24 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-17 14:04:24 -08:00
|
|
|
// We use DECODE_ASYNC here because we just want to get the size information
|
|
|
|
// here and defer the rest of the work.
|
|
|
|
nsresult rv = DecodeSomeOfImage(aImg, DECODE_ASYNC, DECODE_TYPE_UNTIL_SIZE);
|
2013-02-01 17:06:34 -08:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
// If the decoder needs a new frame, enqueue an event to get it; that event
|
|
|
|
// will enqueue another decode request when it's done.
|
|
|
|
if (aImg->mDecoder && aImg->mDecoder->NeedsNewFrame()) {
|
|
|
|
FrameNeededWorker::GetNewFrame(aImg);
|
|
|
|
} else {
|
|
|
|
rv = aImg->FinishedSomeDecoding();
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2012-02-09 12:04:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-03-01 15:17:24 -08:00
|
|
|
RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg,
|
2013-12-17 14:04:24 -08:00
|
|
|
DecodeStrategy aStrategy,
|
2013-03-01 15:17:24 -08:00
|
|
|
DecodeType aDecodeType /* = DECODE_TYPE_UNTIL_TIME */,
|
|
|
|
uint32_t bytesToDecode /* = 0 */)
|
2012-02-09 12:04:30 -08:00
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aImg->mInitialized,
|
|
|
|
"Worker active for uninitialized container!");
|
2013-12-17 14:04:31 -08:00
|
|
|
aImg->mDecodingMonitor.AssertCurrentThreadIn();
|
2012-02-09 12:04:30 -08:00
|
|
|
|
|
|
|
// If an error is flagged, it probably happened while we were waiting
|
|
|
|
// in the event queue.
|
|
|
|
if (aImg->mError)
|
|
|
|
return NS_OK;
|
|
|
|
|
2014-02-26 19:48:47 -08:00
|
|
|
// If there is an error worker pending (say because the main thread has enqueued
|
|
|
|
// another decode request for us before processing the error worker) then bail out.
|
|
|
|
if (aImg->mPendingError)
|
|
|
|
return NS_OK;
|
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
// If mDecoded or we don't have a decoder, we must have finished already (for
|
|
|
|
// example, a synchronous decode request came while the worker was pending).
|
|
|
|
if (!aImg->mDecoder || aImg->mDecoded)
|
|
|
|
return NS_OK;
|
|
|
|
|
2013-03-01 15:17:24 -08:00
|
|
|
// If we're doing synchronous decodes, and we're waiting on a new frame for
|
|
|
|
// this image, get it now.
|
2013-12-17 14:04:24 -08:00
|
|
|
if (aStrategy == DECODE_SYNC && aImg->mDecoder->NeedsNewFrame()) {
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
aImg->mDecoder->AllocateFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're not synchronous, we can't allocate a frame right now.
|
|
|
|
else if (aImg->mDecoder->NeedsNewFrame()) {
|
2013-02-27 11:23:08 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
nsRefPtr<Decoder> decoderKungFuDeathGrip = aImg->mDecoder;
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t maxBytes;
|
2012-02-09 12:04:30 -08:00
|
|
|
if (aImg->mDecoder->IsSizeDecode()) {
|
|
|
|
// Decode all available data if we're a size decode; they're cheap, and we
|
|
|
|
// want them to be more or less synchronous.
|
|
|
|
maxBytes = aImg->mSourceData.Length();
|
|
|
|
} else {
|
|
|
|
// We're only guaranteed to decode this many bytes, so in particular,
|
2014-09-22 14:30:20 -07:00
|
|
|
// gfxPrefs::ImageMemDecodeBytesAtATime should be set high enough for us
|
|
|
|
// to read the size from most images.
|
|
|
|
maxBytes = gfxPrefs::ImageMemDecodeBytesAtATime();
|
2012-02-09 12:04:30 -08:00
|
|
|
}
|
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
if (bytesToDecode == 0) {
|
2014-10-15 13:52:20 -07:00
|
|
|
bytesToDecode = aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded();
|
2013-01-18 13:47:18 -08:00
|
|
|
}
|
|
|
|
|
2014-11-18 12:06:26 -08:00
|
|
|
TimeStamp deadline = TimeStamp::Now() +
|
|
|
|
TimeDuration::FromMilliseconds(gfxPrefs::ImageMemMaxMSBeforeYield());
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2012-03-26 09:05:13 -07:00
|
|
|
// We keep decoding chunks until:
|
|
|
|
// * we don't have any data left to decode,
|
|
|
|
// * the decode completes,
|
|
|
|
// * we're an UNTIL_SIZE decode and we get the size, or
|
|
|
|
// * we run out of time.
|
2013-02-27 11:23:08 -08:00
|
|
|
// We also try to decode at least one "chunk" if we've allocated a new frame,
|
|
|
|
// even if we have no more data to send to the decoder.
|
2014-10-15 13:52:20 -07:00
|
|
|
while ((aImg->mSourceData.Length() > aImg->mDecoder->BytesDecoded() &&
|
2013-02-27 11:23:08 -08:00
|
|
|
bytesToDecode > 0 &&
|
|
|
|
!aImg->IsDecodeFinished() &&
|
|
|
|
!(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) &&
|
|
|
|
!aImg->mDecoder->NeedsNewFrame()) ||
|
2014-11-18 12:06:27 -08:00
|
|
|
aImg->mDecoder->NeedsToFlushData()) {
|
2013-01-18 13:47:18 -08:00
|
|
|
uint32_t chunkSize = std::min(bytesToDecode, maxBytes);
|
2013-12-17 14:04:24 -08:00
|
|
|
nsresult rv = aImg->DecodeSomeData(chunkSize, aStrategy);
|
2012-02-09 12:04:30 -08:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aImg->DoError();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
bytesToDecode -= chunkSize;
|
|
|
|
|
2012-03-26 09:05:13 -07:00
|
|
|
// Yield if we've been decoding for too long. We check this _after_ decoding
|
|
|
|
// a chunk to ensure that we don't yield without doing any decoding.
|
2013-03-01 15:17:24 -08:00
|
|
|
if (aDecodeType == DECODE_TYPE_UNTIL_TIME && TimeStamp::Now() >= deadline)
|
2012-02-09 12:04:30 -08:00
|
|
|
break;
|
2012-03-26 09:05:13 -07:00
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
RasterImage::DecodeDoneWorker::DecodeDoneWorker(RasterImage* image, DecodeRequest* request)
|
|
|
|
: mImage(image)
|
|
|
|
, mRequest(request)
|
|
|
|
{}
|
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
void
|
2014-10-15 16:00:12 -07:00
|
|
|
RasterImage::DecodeDoneWorker::NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request)
|
2013-01-18 13:47:18 -08:00
|
|
|
{
|
2014-10-15 16:00:12 -07:00
|
|
|
image->mDecodingMonitor.AssertCurrentThreadIn();
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
nsCOMPtr<nsIRunnable> worker = new DecodeDoneWorker(image, request);
|
2013-01-18 13:47:18 -08:00
|
|
|
NS_DispatchToMainThread(worker);
|
|
|
|
}
|
2012-02-09 12:04:30 -08:00
|
|
|
|
2013-01-18 13:47:18 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::DecodeDoneWorker::Run()
|
|
|
|
{
|
2013-03-01 15:17:24 -08:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
|
2013-03-01 15:17:24 -08:00
|
|
|
|
2014-10-15 16:00:12 -07:00
|
|
|
mImage->FinishedSomeDecoding(eShutdownIntent_Done, mRequest);
|
2013-01-18 13:47:18 -08:00
|
|
|
|
2012-02-09 12:04:30 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-02-27 11:23:08 -08:00
|
|
|
RasterImage::FrameNeededWorker::FrameNeededWorker(RasterImage* image)
|
|
|
|
: mImage(image)
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
RasterImage::FrameNeededWorker::GetNewFrame(RasterImage* image)
|
|
|
|
{
|
2014-04-03 15:06:26 -07:00
|
|
|
nsCOMPtr<nsIRunnable> worker = new FrameNeededWorker(image);
|
2013-02-27 11:23:08 -08:00
|
|
|
NS_DispatchToMainThread(worker);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RasterImage::FrameNeededWorker::Run()
|
|
|
|
{
|
2013-12-17 14:04:31 -08:00
|
|
|
ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
|
2013-02-27 11:23:08 -08:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
// If we got a synchronous decode in the mean time, we don't need to do
|
|
|
|
// anything.
|
|
|
|
if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
|
|
|
|
rv = mImage->mDecoder->AllocateFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && mImage->mDecoder) {
|
2013-03-01 15:17:24 -08:00
|
|
|
// By definition, we're not done decoding, so enqueue us for more decoding.
|
|
|
|
DecodePool::Singleton()->RequestDecode(mImage);
|
2013-02-27 11:23:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-07-28 14:27:39 -07:00
|
|
|
nsIntSize
|
|
|
|
RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
|
|
|
|
GraphicsFilter aFilter, uint32_t aFlags)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX ||
|
|
|
|
aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX,
|
|
|
|
"Unexpected destination size");
|
|
|
|
|
2014-09-16 16:18:49 -07:00
|
|
|
if (mSize.IsEmpty() || aDest.IsEmpty()) {
|
2014-07-28 14:27:39 -07:00
|
|
|
return nsIntSize(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntSize destSize(ceil(aDest.width), ceil(aDest.height));
|
|
|
|
|
2014-09-19 14:53:29 -07:00
|
|
|
if (CanScale(aFilter, destSize, aFlags)) {
|
|
|
|
DrawableFrameRef frameRef =
|
|
|
|
SurfaceCache::Lookup(ImageKey(this),
|
|
|
|
RasterSurfaceKey(destSize.ToIntSize(),
|
|
|
|
DecodeFlags(aFlags)));
|
|
|
|
|
|
|
|
if (frameRef && frameRef->ImageComplete()) {
|
2014-07-28 14:27:39 -07:00
|
|
|
return destSize; // We have an existing HQ scale for this size.
|
2014-09-14 23:17:28 -07:00
|
|
|
}
|
2014-09-19 14:53:29 -07:00
|
|
|
if (!frameRef) {
|
|
|
|
// We could HQ scale to this size, but we haven't. Request a scale now.
|
2014-09-26 18:50:24 -07:00
|
|
|
frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame), aFlags);
|
2014-09-19 14:53:29 -07:00
|
|
|
if (frameRef) {
|
|
|
|
RequestScale(frameRef.get(), aFlags, destSize);
|
|
|
|
}
|
2014-09-16 22:30:11 -07:00
|
|
|
}
|
2014-07-28 14:27:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We either can't HQ scale to this size or the scaled version isn't ready
|
|
|
|
// yet. Use our intrinsic size for now.
|
|
|
|
return mSize;
|
|
|
|
}
|
|
|
|
|
2012-01-06 08:02:27 -08:00
|
|
|
} // namespace image
|
2010-08-13 21:09:49 -07:00
|
|
|
} // namespace mozilla
|