Bug 795940 - Part 0.5 - Move ScaleRequest and the runners into the CPP file so consumers don't have to care about them. BY THE DEMAND OF AND r=jrmuizel

--HG--
extra : rebase_source : eeb96eb9680017d2be9ee99ac0c760249a74bcbe
This commit is contained in:
Joe Drew 2012-10-12 18:24:47 -04:00
parent 4baaf41686
commit 21be03f840
2 changed files with 228 additions and 237 deletions

View File

@ -140,6 +140,195 @@ DiscardingEnabled()
return enabled;
}
struct ScaleRequest
{
ScaleRequest(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
: scale(aScale)
, dstLocked(false)
, done(false)
, stopped(false)
{
MOZ_ASSERT(!aSrcFrame->GetIsPaletted());
MOZ_ASSERT(aScale.width > 0 && aScale.height > 0);
weakImage = aImage->asWeakPtr();
srcRect = aSrcFrame->GetRect();
dstSize.width = NSToIntRoundUp(srcRect.width * scale.width);
dstSize.height = NSToIntRoundUp(srcRect.height * scale.height);
}
// This can only be called on the main thread.
bool GetSurfaces(imgFrame* srcFrame)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<RasterImage> image = weakImage.get();
if (!image) {
return false;
}
bool success = false;
if (!dstLocked) {
bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData());
dstLocked = NS_SUCCEEDED(dstFrame->LockImageData());
nsRefPtr<gfxASurface> dstASurf;
nsRefPtr<gfxASurface> srcASurf;
success = srcLocked && NS_SUCCEEDED(srcFrame->GetSurface(getter_AddRefs(srcASurf)));
success = success && dstLocked && NS_SUCCEEDED(dstFrame->GetSurface(getter_AddRefs(dstASurf)));
success = success && srcLocked && dstLocked && srcASurf && dstASurf;
if (success) {
srcSurface = srcASurf->GetAsImageSurface();
dstSurface = dstASurf->GetAsImageSurface();
srcData = srcSurface->Data();
dstData = dstSurface->Data();
srcStride = srcSurface->Stride();
dstStride = dstSurface->Stride();
srcFormat = mozilla::gfx::ImageFormatToSurfaceFormat(srcFrame->GetFormat());
}
// We have references to the Thebes surfaces, so we don't need to leave
// the source frame (that we don't own) locked. We'll unlock the
// destination frame in ReleaseSurfaces(), below.
if (srcLocked) {
success = NS_SUCCEEDED(srcFrame->UnlockImageData()) && success;
}
success = success && srcSurface && dstSurface;
}
return success;
}
// This can only be called on the main thread.
bool ReleaseSurfaces()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<RasterImage> image = weakImage.get();
if (!image) {
return false;
}
bool success = false;
if (dstLocked) {
success = NS_SUCCEEDED(dstFrame->UnlockImageData());
dstLocked = false;
srcData = nullptr;
dstData = nullptr;
srcSurface = nullptr;
dstSurface = nullptr;
}
return success;
}
// These values may only be touched on the main thread.
WeakPtr<RasterImage> weakImage;
nsAutoPtr<imgFrame> dstFrame;
nsRefPtr<gfxImageSurface> srcSurface;
nsRefPtr<gfxImageSurface> dstSurface;
// Below are the values that may be touched on the scaling thread.
gfxSize scale;
uint8_t* srcData;
uint8_t* dstData;
nsIntRect srcRect;
gfxIntSize dstSize;
uint32_t srcStride;
uint32_t dstStride;
mozilla::gfx::SurfaceFormat srcFormat;
bool dstLocked;
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:
DrawRunner(ScaleRequest* request)
: mScaleRequest(request)
{}
NS_IMETHOD Run()
{
// ScaleWorker is finished with this request, so we can unlock the data now.
mScaleRequest->ReleaseSurfaces();
nsRefPtr<RasterImage> image = mScaleRequest->weakImage.get();
if (image) {
RasterImage::ScaleStatus status;
if (mScaleRequest->done) {
status = RasterImage::SCALE_DONE;
} else {
status = RasterImage::SCALE_INVALID;
}
image->ScalingDone(mScaleRequest, status);
}
return NS_OK;
}
private: /* members */
nsAutoPtr<ScaleRequest> mScaleRequest;
};
class ScaleRunner : public nsRunnable
{
public:
ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
{
nsAutoPtr<ScaleRequest> request(new ScaleRequest(aImage, aScale, aSrcFrame));
// Destination is unconditionally ARGB32 because that's what the scaler
// outputs.
request->dstFrame = new imgFrame();
nsresult rv = request->dstFrame->Init(0, 0, request->dstSize.width, request->dstSize.height,
gfxASurface::ImageFormatARGB32);
if (NS_FAILED(rv) || !request->GetSurfaces(aSrcFrame)) {
return;
}
aImage->ScalingStart(request);
mScaleRequest = request;
}
NS_IMETHOD Run()
{
// An alias just for ease of typing
ScaleRequest* request = mScaleRequest;
if (!request->stopped) {
request->done = mozilla::gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride,
request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride,
request->srcFormat);
} else {
request->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, NS_DISPATCH_NORMAL);
return NS_OK;
}
bool IsOK() const { return !!mScaleRequest; }
private:
nsAutoPtr<ScaleRequest> mScaleRequest;
};
namespace mozilla {
namespace image {
@ -2618,83 +2807,6 @@ RasterImage::SyncDecode()
return mError ? NS_ERROR_FAILURE : NS_OK;
}
nsresult
RasterImage::ScaleRunner::Run()
{
// An alias just for ease of typing
ScaleRequest* request = mScaleRequest;
if (!request->stopped) {
request->done = mozilla::gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride,
request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride,
request->srcFormat);
} else {
request->done = false;
}
// OK, we've got a new scaled image. Let's get the main thread to unlock and
// redraw it.
DrawRunner* runner = new DrawRunner(mScaleRequest.forget());
NS_DispatchToMainThread(runner, NS_DISPATCH_NORMAL);
return NS_OK;
}
RasterImage::ScaleRunner::ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
{
nsAutoPtr<ScaleRequest> request(new ScaleRequest(aImage, aScale, aSrcFrame));
// Destination is unconditionally ARGB32 because that's what the scaler
// outputs.
request->dstFrame = new imgFrame();
nsresult rv = request->dstFrame->Init(0, 0, request->dstSize.width, request->dstSize.height,
gfxASurface::ImageFormatARGB32);
if (NS_FAILED(rv) || !request->GetSurfaces(aSrcFrame)) {
return;
}
aImage->ScalingStart(request);
mScaleRequest = request;
}
RasterImage::DrawRunner::DrawRunner(ScaleRequest* request)
: mScaleRequest(request)
{}
nsresult
RasterImage::DrawRunner::Run()
{
// ScaleWorker is finished with this request, so we can unlock the data now.
mScaleRequest->ReleaseSurfaces();
nsRefPtr<RasterImage> image = mScaleRequest->weakImage.get();
// Only set the scale result if the request finished successfully.
if (mScaleRequest->done && image) {
nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(image->mObserver));
if (observer) {
imgFrame *scaledFrame = mScaleRequest->dstFrame.get();
scaledFrame->ImageUpdated(scaledFrame->GetRect());
observer->FrameChanged(&mScaleRequest->srcRect);
}
}
if (image) {
ScaleStatus status;
if (mScaleRequest->done) {
status = SCALE_DONE;
} else {
status = SCALE_INVALID;
}
image->ScalingDone(mScaleRequest, status);
}
return NS_OK;
}
static inline bool
IsDownscale(const gfxSize& scale)
{
@ -2741,6 +2853,14 @@ RasterImage::ScalingDone(ScaleRequest* request, ScaleStatus status)
if (status == SCALE_DONE) {
MOZ_ASSERT(request->done);
nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
if (observer) {
imgFrame *scaledFrame = request->dstFrame.get();
scaledFrame->ImageUpdated(scaledFrame->GetRect());
observer->FrameChanged(&request->srcRect);
}
mScaleResult.status = SCALE_DONE;
mScaleResult.frame = request->dstFrame;
mScaleResult.scale = request->scale;

View File

@ -125,6 +125,8 @@ class nsIInputStream;
* in Init().
*/
class ScaleRequest;
namespace mozilla {
namespace layers {
class LayerManager;
@ -314,6 +316,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);
private:
struct Anim
{
@ -473,156 +492,6 @@ private:
bool mPendingInEventLoop;
};
struct ScaleRequest
{
ScaleRequest(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
: scale(aScale)
, dstLocked(false)
, done(false)
, stopped(false)
{
MOZ_ASSERT(!aSrcFrame->GetIsPaletted());
MOZ_ASSERT(aScale.width > 0 && aScale.height > 0);
weakImage = aImage->asWeakPtr();
srcRect = aSrcFrame->GetRect();
dstSize.width = NSToIntRoundUp(srcRect.width * scale.width);
dstSize.height = NSToIntRoundUp(srcRect.height * scale.height);
}
// This can only be called on the main thread.
bool GetSurfaces(imgFrame* srcFrame)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<RasterImage> image = weakImage.get();
if (!image) {
return false;
}
bool success = false;
if (!dstLocked) {
bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData());
dstLocked = NS_SUCCEEDED(dstFrame->LockImageData());
nsRefPtr<gfxASurface> dstASurf;
nsRefPtr<gfxASurface> srcASurf;
success = srcLocked && NS_SUCCEEDED(srcFrame->GetSurface(getter_AddRefs(srcASurf)));
success = success && dstLocked && NS_SUCCEEDED(dstFrame->GetSurface(getter_AddRefs(dstASurf)));
success = success && srcLocked && dstLocked && srcASurf && dstASurf;
if (success) {
srcSurface = srcASurf->GetAsImageSurface();
dstSurface = dstASurf->GetAsImageSurface();
srcData = srcSurface->Data();
dstData = dstSurface->Data();
srcStride = srcSurface->Stride();
dstStride = dstSurface->Stride();
srcFormat = mozilla::gfx::ImageFormatToSurfaceFormat(srcFrame->GetFormat());
}
// We have references to the Thebes surfaces, so we don't need to leave
// the source frame (that we don't own) locked. We'll unlock the
// destination frame in ReleaseSurfaces(), below.
if (srcLocked) {
success = NS_SUCCEEDED(srcFrame->UnlockImageData()) && success;
}
success = success && srcSurface && dstSurface;
}
return success;
}
// This can only be called on the main thread.
bool ReleaseSurfaces()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<RasterImage> image = weakImage.get();
if (!image) {
return false;
}
bool success = false;
if (dstLocked) {
success = NS_SUCCEEDED(dstFrame->UnlockImageData());
dstLocked = false;
srcData = nullptr;
dstData = nullptr;
srcSurface = nullptr;
dstSurface = nullptr;
}
return success;
}
// These values may only be touched on the main thread.
WeakPtr<RasterImage> weakImage;
nsAutoPtr<imgFrame> dstFrame;
nsRefPtr<gfxImageSurface> srcSurface;
nsRefPtr<gfxImageSurface> dstSurface;
// Below are the values that may be touched on the scaling thread.
gfxSize scale;
uint8_t* srcData;
uint8_t* dstData;
nsIntRect srcRect;
gfxIntSize dstSize;
uint32_t srcStride;
uint32_t dstStride;
mozilla::gfx::SurfaceFormat srcFormat;
bool dstLocked;
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;
};
enum ScaleStatus
{
SCALE_INVALID,
SCALE_PENDING,
SCALE_DONE
};
struct ScaleResult
{
ScaleResult()
: status(SCALE_INVALID)
{}
gfxSize scale;
nsAutoPtr<imgFrame> frame;
ScaleStatus status;
};
class ScaleRunner : public nsRunnable
{
public:
ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame);
NS_IMETHOD Run();
bool IsOK() const { return !!mScaleRequest; }
private:
nsAutoPtr<ScaleRequest> mScaleRequest;
};
class DrawRunner : public nsRunnable
{
public:
DrawRunner(ScaleRequest* request);
NS_IMETHOD Run();
private: /* members */
nsAutoPtr<ScaleRequest> mScaleRequest;
};
void DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
gfxContext *aContext,
gfxPattern::GraphicsFilter aFilter,
@ -630,16 +499,6 @@ private:
const gfxRect &aFill,
const nsIntRect &aSubimage);
// 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);
/**
* Advances the animation. Typically, this will advance a single frame, but it
* may advance multiple frames. This may happen if we have infrequently
@ -851,6 +710,18 @@ private: // data
TimeStamp mDrawStartTime;
inline bool CanScale(gfxPattern::GraphicsFilter aFilter, gfxSize aScale);
struct ScaleResult
{
ScaleResult()
: status(SCALE_INVALID)
{}
gfxSize scale;
nsAutoPtr<imgFrame> frame;
ScaleStatus status;
};
ScaleResult mScaleResult;
// We hold on to a bare pointer to a ScaleRequest while it's outstanding so