mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset d295c8ec4b5b (bug 1060200)
This commit is contained in:
parent
46c8dedeae
commit
8c120cffff
@ -24,7 +24,6 @@
|
||||
#include "nsIThreadPool.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "SurfaceCache.h"
|
||||
#include "FrameAnimator.h"
|
||||
|
||||
#include "nsPNGDecoder.h"
|
||||
@ -68,12 +67,6 @@ using std::ceil;
|
||||
#define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
|
||||
#define DECODE_FLAGS_DEFAULT 0
|
||||
|
||||
static uint32_t
|
||||
DecodeFlags(uint32_t aFlags)
|
||||
{
|
||||
return aFlags & DECODE_FLAGS_MASK;
|
||||
}
|
||||
|
||||
/* Accounting for compressed data */
|
||||
#if defined(PR_LOGGING)
|
||||
static PRLogModuleInfo *
|
||||
@ -191,141 +184,184 @@ DiscardingEnabled()
|
||||
return enabled;
|
||||
}
|
||||
|
||||
class ScaleRunner : public nsRunnable
|
||||
class ScaleRequest
|
||||
{
|
||||
enum ScaleState
|
||||
{
|
||||
eNew,
|
||||
eReady,
|
||||
eFinish,
|
||||
eFinishWithError
|
||||
};
|
||||
|
||||
public:
|
||||
ScaleRunner(RasterImage* aImage,
|
||||
uint32_t aImageFlags,
|
||||
const nsIntSize& aSize,
|
||||
RawAccessFrameRef&& aSrcRef)
|
||||
: mImage(aImage)
|
||||
, mSrcRef(Move(aSrcRef))
|
||||
, mDstSize(aSize)
|
||||
, mImageFlags(aImageFlags)
|
||||
, mState(eNew)
|
||||
ScaleRequest(RasterImage* aImage,
|
||||
const nsIntSize& aSize,
|
||||
RawAccessFrameRef&& aSrcRef)
|
||||
: weakImage(aImage)
|
||||
, srcRef(Move(aSrcRef))
|
||||
, srcRect(srcRef->GetRect())
|
||||
, dstSize(aSize)
|
||||
, done(false)
|
||||
, stopped(false)
|
||||
{
|
||||
MOZ_ASSERT(!mSrcRef->GetIsPaletted());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!srcRef->GetIsPaletted());
|
||||
MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
|
||||
}
|
||||
|
||||
bool Init()
|
||||
// This can only be called on the main thread.
|
||||
bool AcquireResources()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mState == eNew, "Calling Init() twice?");
|
||||
|
||||
// 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)) {
|
||||
nsRefPtr<RasterImage> image = weakImage.get();
|
||||
if (!image) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (!dstFrame) {
|
||||
// We need to hold a lock onto the RasterImage object itself so that
|
||||
// it (and its associated imgFrames) aren't marked as discardable.
|
||||
if (NS_FAILED(image->LockImage())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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(dstSize, SurfaceFormat::B8G8R8A8);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
dstFrame = tentativeDstFrame.forget();
|
||||
dstRef = Move(tentativeDstRef);
|
||||
}
|
||||
|
||||
// Everything worked, so commit to these objects and mark ourselves ready.
|
||||
mDstRef = Move(tentativeDstRef);
|
||||
mState = eReady;
|
||||
|
||||
// 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));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
~ScaleRunner()
|
||||
// This can only be called on the main thread.
|
||||
void ReleaseResources()
|
||||
{
|
||||
MOZ_ASSERT(!mSrcRef && !mDstRef,
|
||||
"Should have released strong refs in Run()");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<RasterImage> image = weakImage.get();
|
||||
if (image) {
|
||||
image->UnlockImage();
|
||||
}
|
||||
|
||||
if (DiscardingEnabled() && dstFrame) {
|
||||
dstFrame->SetDiscardable();
|
||||
}
|
||||
|
||||
// Release everything except dstFrame, which we keep around for RasterImage
|
||||
// to retrieve.
|
||||
srcRef.reset();
|
||||
dstRef.reset();
|
||||
}
|
||||
|
||||
// These values may only be modified on the main thread.
|
||||
WeakPtr<RasterImage> weakImage;
|
||||
nsRefPtr<imgFrame> dstFrame;
|
||||
RawAccessFrameRef srcRef;
|
||||
RawAccessFrameRef dstRef;
|
||||
|
||||
// Below are the values that may be modified on the scaling thread.
|
||||
nsIntRect srcRect;
|
||||
nsIntSize dstSize;
|
||||
bool done;
|
||||
|
||||
// This boolean is accessed from both threads simultaneously without locking.
|
||||
// That's safe because stopping a ScaleRequest is strictly an optimization;
|
||||
// if we're not cache-coherent, at worst we'll do extra work.
|
||||
bool stopped;
|
||||
};
|
||||
|
||||
class DrawRunner : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit DrawRunner(ScaleRequest* request)
|
||||
: mScaleRequest(request)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
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();
|
||||
// Grab the weak image pointer before the request releases it.
|
||||
nsRefPtr<RasterImage> image = mScaleRequest->weakImage.get();
|
||||
|
||||
// Actually do the scaling.
|
||||
bool succeeded =
|
||||
gfx::Scale(srcData, srcSize.width, srcSize.height, srcStride,
|
||||
dstData, mDstSize.width, mDstSize.height, dstStride,
|
||||
srcFormat);
|
||||
// ScaleWorker is finished with this request, so release everything that we
|
||||
// don't need anymore.
|
||||
mScaleRequest->ReleaseResources();
|
||||
|
||||
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();
|
||||
}
|
||||
if (image) {
|
||||
RasterImage::ScaleStatus status;
|
||||
if (mScaleRequest->done) {
|
||||
status = RasterImage::SCALE_DONE;
|
||||
} else {
|
||||
status = RasterImage::SCALE_INVALID;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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");
|
||||
image->ScalingDone(mScaleRequest, status);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private: /* members */
|
||||
nsAutoPtr<ScaleRequest> mScaleRequest;
|
||||
};
|
||||
|
||||
class ScaleRunner : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ScaleRunner(RasterImage* aImage,
|
||||
const nsIntSize& aSize,
|
||||
RawAccessFrameRef&& aSrcRef)
|
||||
{
|
||||
nsAutoPtr<ScaleRequest> req(new ScaleRequest(aImage, aSize, Move(aSrcRef)));
|
||||
if (!req->AcquireResources()) {
|
||||
return;
|
||||
}
|
||||
|
||||
aImage->ScalingStart(req);
|
||||
mScaleRequest = req;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
ScaleRequest* req = mScaleRequest.get();
|
||||
|
||||
if (!req->stopped) {
|
||||
// Collect information from the frames that we need to scale.
|
||||
uint8_t* srcData = req->srcRef->GetImageData();
|
||||
uint8_t* dstData = req->dstRef->GetImageData();
|
||||
uint32_t srcStride = req->srcRef->GetImageBytesPerRow();
|
||||
uint32_t dstStride = req->dstRef->GetImageBytesPerRow();
|
||||
SurfaceFormat srcFormat = req->srcRef->GetFormat();
|
||||
|
||||
// Actually do the scaling.
|
||||
req->done =
|
||||
gfx::Scale(srcData, req->srcRect.width, req->srcRect.height, srcStride,
|
||||
dstData, req->dstSize.width, req->dstSize.height, dstStride,
|
||||
srcFormat);
|
||||
} else {
|
||||
req->done = false;
|
||||
}
|
||||
|
||||
// OK, we've got a new scaled image. Let's get the main thread to unlock and
|
||||
// redraw it.
|
||||
nsRefPtr<DrawRunner> runner = new DrawRunner(mScaleRequest.forget());
|
||||
NS_DispatchToMainThread(runner);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool IsOK() const { return !!mScaleRequest; }
|
||||
|
||||
private:
|
||||
WeakPtr<RasterImage> mImage;
|
||||
RawAccessFrameRef mSrcRef;
|
||||
RawAccessFrameRef mDstRef;
|
||||
const nsIntSize mDstSize;
|
||||
uint32_t mImageFlags;
|
||||
ScaleState mState;
|
||||
nsAutoPtr<ScaleRequest> mScaleRequest;
|
||||
};
|
||||
|
||||
/* static */ StaticRefPtr<RasterImage::DecodePool> RasterImage::DecodePool::sSingleton;
|
||||
@ -367,7 +403,8 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
|
||||
mFinishing(false),
|
||||
mInUpdateImageContainer(false),
|
||||
mWantFullDecode(false),
|
||||
mPendingError(false)
|
||||
mPendingError(false),
|
||||
mScaleRequest(nullptr)
|
||||
{
|
||||
mStatusTrackerInit = new imgStatusTrackerInit(this, aStatusTracker);
|
||||
|
||||
@ -415,9 +452,6 @@ RasterImage::~RasterImage()
|
||||
}
|
||||
}
|
||||
|
||||
// Release any HQ scaled frames from the surface cache.
|
||||
SurfaceCache::Discard(this);
|
||||
|
||||
mAnim = nullptr;
|
||||
|
||||
// Total statistics
|
||||
@ -1034,7 +1068,13 @@ size_t
|
||||
RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
|
||||
MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return mFrameBlender.SizeOfDecodedWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
|
||||
size_t n = mFrameBlender.SizeOfDecodedWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
|
||||
|
||||
if (mScaleResult.status == SCALE_DONE) {
|
||||
n += mScaleResult.frame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -1905,6 +1945,10 @@ RasterImage::Discard(bool force)
|
||||
// Delete all the decoded frames
|
||||
mFrameBlender.Discard();
|
||||
|
||||
// Clear our downscaled frame.
|
||||
mScaleResult.status = SCALE_INVALID;
|
||||
mScaleResult.frame = nullptr;
|
||||
|
||||
// Clear the last decoded multipart frame.
|
||||
mMultipartDecodedFrame = nullptr;
|
||||
|
||||
@ -2477,85 +2521,105 @@ RasterImage::SyncDecode()
|
||||
}
|
||||
|
||||
bool
|
||||
RasterImage::CanScale(GraphicsFilter aFilter,
|
||||
const nsIntSize& aSize,
|
||||
uint32_t aFlags)
|
||||
RasterImage::CanQualityScale(const gfx::Size& scale)
|
||||
{
|
||||
#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.
|
||||
if (!gHQDownscaling || !mDecoded ||
|
||||
!(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING) ||
|
||||
aFilter != GraphicsFilter::FILTER_GOOD) {
|
||||
// If target size is 1:1 with original, don't scale.
|
||||
if (scale.width == 1.0 && scale.height == 1.0)
|
||||
return false;
|
||||
|
||||
// To save memory don't quality upscale images bigger than the limit.
|
||||
if (scale.width > 1.0 || scale.height > 1.0) {
|
||||
uint32_t scaled_size = static_cast<uint32_t>(mSize.width * mSize.height * scale.width * scale.height);
|
||||
if (scaled_size > gHQUpscalingMaxSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RasterImage::CanScale(GraphicsFilter aFilter, gfx::Size aScale, uint32_t aFlags)
|
||||
{
|
||||
// The high-quality scaler requires Skia.
|
||||
#ifdef MOZ_ENABLE_SKIA
|
||||
// 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.
|
||||
if (mAnim || mMultipart) {
|
||||
return false;
|
||||
}
|
||||
// We only use the scaler when drawing to the window because, if we're not
|
||||
// drawing to a window (eg a canvas), updates to that image will be ignored.
|
||||
if (gHQDownscaling && aFilter == GraphicsFilter::FILTER_GOOD &&
|
||||
!mAnim && mDecoded && !mMultipart && CanQualityScale(aScale) &&
|
||||
(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
|
||||
gfxFloat factor = gHQDownscalingMinFactor / 1000.0;
|
||||
|
||||
// If target size is 1:1 with original, don't scale.
|
||||
if (aSize == mSize) {
|
||||
return false;
|
||||
return (aScale.width < factor || aScale.height < factor);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (scaledSize > gHQUpscalingMaxSize) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// There's no point in scaling if we can't store the result.
|
||||
if (!SurfaceCache::CanHold(aSize.ToIntSize())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX(seth): It's not clear what this check buys us over gHQUpscalingMaxSize.
|
||||
// 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);
|
||||
gfxFloat minFactor = gHQDownscalingMinFactor / 1000.0;
|
||||
return (scale.width < minFactor || scale.height < minFactor);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::NotifyNewScaledFrame()
|
||||
RasterImage::ScalingStart(ScaleRequest* request)
|
||||
{
|
||||
if (mStatusTracker) {
|
||||
// Send an invalidation so observers will repaint and can take advantage of
|
||||
// the new scaled frame if possible.
|
||||
// XXX(seth): Why does FrameChanged take a pointer and not a reference?
|
||||
nsIntRect invalidationRect(0, 0, mSize.width, mSize.height);
|
||||
mStatusTracker->FrameChanged(&invalidationRect);
|
||||
MOZ_ASSERT(request);
|
||||
mScaleResult.scaledSize = request->dstSize;
|
||||
mScaleResult.status = SCALE_PENDING;
|
||||
mScaleRequest = request;
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::ScalingDone(ScaleRequest* request, ScaleStatus status)
|
||||
{
|
||||
MOZ_ASSERT(status == SCALE_DONE || status == SCALE_INVALID);
|
||||
MOZ_ASSERT(request);
|
||||
|
||||
if (status == SCALE_DONE) {
|
||||
MOZ_ASSERT(request->done);
|
||||
|
||||
mScaleResult.status = SCALE_DONE;
|
||||
mScaleResult.frame = request->dstFrame.forget();
|
||||
mScaleResult.scaledSize = request->dstSize;
|
||||
|
||||
mScaleResult.frame->ImageUpdated(mScaleResult.frame->GetRect());
|
||||
|
||||
if (mStatusTracker) {
|
||||
mStatusTracker->FrameChanged(&request->srcRect);
|
||||
}
|
||||
} else {
|
||||
mScaleResult.status = SCALE_INVALID;
|
||||
mScaleResult.frame = nullptr;
|
||||
}
|
||||
|
||||
// If we were waiting for this scale to come through, forget the scale
|
||||
// request. Otherwise, we still have a scale outstanding that it's possible
|
||||
// for us to (want to) stop.
|
||||
if (mScaleRequest == request) {
|
||||
mScaleRequest = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::RequestScale(imgFrame* aFrame,
|
||||
uint32_t aFlags,
|
||||
const nsIntSize& aSize)
|
||||
RasterImage::RequestScale(imgFrame* aFrame, nsIntSize aSize)
|
||||
{
|
||||
// We can't scale if we can't lock the image data for this frame.
|
||||
// We can't store more than one scaled version of an image right now, so if
|
||||
// there's more than one instance of this image, bail.
|
||||
if (mLockCount != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We also can't scale if we can't lock the image data for this frame.
|
||||
RawAccessFrameRef frameRef = aFrame->RawAccessRef();
|
||||
if (!frameRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ScaleRunner> runner =
|
||||
new ScaleRunner(this, DecodeFlags(aFlags), aSize, Move(frameRef));
|
||||
if (runner->Init()) {
|
||||
// If we have an outstanding request, signal it to stop (if it can).
|
||||
if (mScaleRequest) {
|
||||
mScaleRequest->stopped = true;
|
||||
}
|
||||
|
||||
nsRefPtr<ScaleRunner> runner = new ScaleRunner(this, aSize, Move(frameRef));
|
||||
if (runner->IsOK()) {
|
||||
if (!sScaleWorkerThread) {
|
||||
NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread));
|
||||
ClearOnShutdown(&sScaleWorkerThread);
|
||||
@ -2574,20 +2638,24 @@ RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
DrawableFrameRef frameRef;
|
||||
gfx::Size scale(double(aSize.width) / mSize.width,
|
||||
double(aSize.height) / mSize.height);
|
||||
|
||||
if (CanScale(aFilter, aSize, aFlags) && !aFrameRef->IsSinglePixel()) {
|
||||
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);
|
||||
if (CanScale(aFilter, scale, aFlags) && !aFrameRef->IsSinglePixel()) {
|
||||
// FIXME: Current implementation doesn't support pre-downscale
|
||||
// mechanism for multiple sizes from same src, since we cache
|
||||
// pre-downscaled frame only for the latest requested scale.
|
||||
// The solution is to cache more than one scaled image frame
|
||||
// for each RasterImage.
|
||||
if (mScaleResult.status == SCALE_DONE && mScaleResult.scaledSize == aSize) {
|
||||
frameRef = mScaleResult.frame->DrawableRef();
|
||||
}
|
||||
if (frameRef && !frameRef->ImageComplete()) {
|
||||
frameRef.reset(); // We're still scaling, so we can't use this yet.
|
||||
if (!frameRef &&
|
||||
(mScaleResult.status != SCALE_PENDING || mScaleResult.scaledSize != aSize)) {
|
||||
// We either didn't have a complete scaled frame, it didn't match, or the
|
||||
// OS threw it away. Fall back to aFrame, and request a new scaled frame
|
||||
// if we're not already working on the one we need.
|
||||
RequestScale(aFrameRef.get(), aSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2601,8 +2669,6 @@ RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
|
||||
// adjust the drawing parameters accordingly.
|
||||
nsIntRect finalFrameRect = frameRef->GetRect();
|
||||
if (finalFrameRect.Size() != aSize) {
|
||||
gfx::Size scale(double(aSize.width) / mSize.width,
|
||||
double(aSize.height) / mSize.height);
|
||||
aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
|
||||
region.Scale(1.0 / scale.width, 1.0 / scale.height);
|
||||
}
|
||||
@ -3603,23 +3669,23 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
|
||||
}
|
||||
|
||||
nsIntSize destSize(ceil(aDest.width), ceil(aDest.height));
|
||||
gfx::Size scale(double(destSize.width) / mSize.width,
|
||||
double(destSize.height) / mSize.height);
|
||||
|
||||
if (CanScale(aFilter, destSize, aFlags)) {
|
||||
DrawableFrameRef frameRef =
|
||||
SurfaceCache::Lookup(ImageKey(this),
|
||||
RasterSurfaceKey(destSize.ToIntSize(),
|
||||
DecodeFlags(aFlags)));
|
||||
|
||||
if (frameRef && frameRef->ImageComplete()) {
|
||||
if (CanScale(aFilter, scale, aFlags)) {
|
||||
if (mScaleResult.scaledSize == destSize) {
|
||||
if (mScaleResult.status == SCALE_DONE) {
|
||||
return destSize; // We have an existing HQ scale for this size.
|
||||
}
|
||||
if (!frameRef) {
|
||||
// We could HQ scale to this size, but we haven't. Request a scale now.
|
||||
frameRef = GetFrame(GetRequestedFrameIndex(aWhichFrame));
|
||||
if (frameRef) {
|
||||
RequestScale(frameRef.get(), aFlags, destSize);
|
||||
} else if (mScaleResult.status == SCALE_PENDING) {
|
||||
return mSize; // We're waiting for exactly this result.
|
||||
}
|
||||
}
|
||||
|
||||
// If there's only one instance of this image on this page, ask for a scale.
|
||||
DrawableFrameRef frameRef = GetFrame(GetRequestedFrameIndex(aWhichFrame));
|
||||
if (frameRef) {
|
||||
RequestScale(frameRef.get(), destSize);
|
||||
}
|
||||
}
|
||||
|
||||
// We either can't HQ scale to this size or the scaled version isn't ready
|
||||
|
@ -132,9 +132,9 @@ class Image;
|
||||
|
||||
namespace image {
|
||||
|
||||
class ScaleRequest;
|
||||
class Decoder;
|
||||
class FrameAnimator;
|
||||
class ScaleRunner;
|
||||
|
||||
class RasterImage MOZ_FINAL : public ImageResource
|
||||
, public nsIProperties
|
||||
@ -298,6 +298,23 @@ public:
|
||||
// Called from module startup. Sets up RasterImage to be used.
|
||||
static void Initialize();
|
||||
|
||||
enum ScaleStatus
|
||||
{
|
||||
SCALE_INVALID,
|
||||
SCALE_PENDING,
|
||||
SCALE_DONE
|
||||
};
|
||||
|
||||
// Call this with a new ScaleRequest to mark this RasterImage's scale result
|
||||
// as waiting for the results of this request. You call to ScalingDone before
|
||||
// request is destroyed!
|
||||
void ScalingStart(ScaleRequest* request);
|
||||
|
||||
// Call this with a finished ScaleRequest to set this RasterImage's scale
|
||||
// result. Give it a ScaleStatus of SCALE_DONE if everything succeeded, and
|
||||
// SCALE_INVALID otherwise.
|
||||
void ScalingDone(ScaleRequest* request, ScaleStatus status);
|
||||
|
||||
// Decoder shutdown
|
||||
enum eShutdownIntent {
|
||||
eShutdownIntent_Done = 0,
|
||||
@ -309,6 +326,9 @@ public:
|
||||
// Decode strategy
|
||||
|
||||
private:
|
||||
// Initiates an HQ scale for the given frame, if possible.
|
||||
void RequestScale(imgFrame* aFrame, nsIntSize aScale);
|
||||
|
||||
already_AddRefed<imgStatusTracker> CurrentStatusTracker()
|
||||
{
|
||||
mDecodingMonitor.AssertCurrentThreadIn();
|
||||
@ -704,28 +724,32 @@ private: // data
|
||||
bool IsDecodeFinished();
|
||||
TimeStamp mDrawStartTime;
|
||||
|
||||
inline bool CanQualityScale(const gfx::Size& scale);
|
||||
inline bool CanScale(GraphicsFilter aFilter, gfx::Size aScale, uint32_t aFlags);
|
||||
|
||||
struct ScaleResult
|
||||
{
|
||||
ScaleResult()
|
||||
: status(SCALE_INVALID)
|
||||
{}
|
||||
|
||||
nsIntSize scaledSize;
|
||||
nsRefPtr<imgFrame> frame;
|
||||
ScaleStatus status;
|
||||
};
|
||||
|
||||
ScaleResult mScaleResult;
|
||||
|
||||
// We hold on to a bare pointer to a ScaleRequest while it's outstanding so
|
||||
// we can mark it as stopped if necessary. The ScaleWorker/DrawWorker duo
|
||||
// will inform us when to let go of this pointer.
|
||||
ScaleRequest* mScaleRequest;
|
||||
|
||||
// Initializes imgStatusTracker and resets it on RasterImage destruction.
|
||||
nsAutoPtr<imgStatusTrackerInit> mStatusTrackerInit;
|
||||
|
||||
nsresult ShutdownDecoder(eShutdownIntent aIntent);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Scaling.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initiates an HQ scale for the given frame, if possible.
|
||||
void RequestScale(imgFrame* aFrame, uint32_t aFlags, const nsIntSize& aSize);
|
||||
|
||||
// Determines whether we can perform an HQ scale with the given parameters.
|
||||
bool CanScale(GraphicsFilter aFilter, const nsIntSize& aSize, uint32_t aFlags);
|
||||
|
||||
// Called by the HQ scaler when a new scaled frame is ready.
|
||||
void NotifyNewScaledFrame();
|
||||
|
||||
friend class ScaleRunner;
|
||||
|
||||
|
||||
// Error handling.
|
||||
void DoError();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user