From 21be03f8403352022a9ca38c9bf7763204d70bca Mon Sep 17 00:00:00 2001 From: Joe Drew Date: Fri, 12 Oct 2012 18:24:47 -0400 Subject: [PATCH] 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 --- image/src/RasterImage.cpp | 274 +++++++++++++++++++++++++++----------- image/src/RasterImage.h | 191 +++++--------------------- 2 files changed, 228 insertions(+), 237 deletions(-) diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 537be0bc76ca..f886a2fd6aa9 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -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 image = weakImage.get(); + if (!image) { + return false; + } + + bool success = false; + if (!dstLocked) { + bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData()); + dstLocked = NS_SUCCEEDED(dstFrame->LockImageData()); + + nsRefPtr dstASurf; + nsRefPtr 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 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 weakImage; + nsAutoPtr dstFrame; + nsRefPtr srcSurface; + nsRefPtr 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 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 mScaleRequest; +}; + +class ScaleRunner : public nsRunnable +{ +public: + ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame) + { + nsAutoPtr 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 runner = new DrawRunner(mScaleRequest.forget()); + NS_DispatchToMainThread(runner, NS_DISPATCH_NORMAL); + + return NS_OK; + } + + bool IsOK() const { return !!mScaleRequest; } + +private: + nsAutoPtr 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 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 image = mScaleRequest->weakImage.get(); - - // Only set the scale result if the request finished successfully. - if (mScaleRequest->done && image) { - nsCOMPtr 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 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; diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 83110428b945..d934b8cf0817 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -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 image = weakImage.get(); - if (!image) { - return false; - } - - bool success = false; - if (!dstLocked) { - bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData()); - dstLocked = NS_SUCCEEDED(dstFrame->LockImageData()); - - nsRefPtr dstASurf; - nsRefPtr 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 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 weakImage; - nsAutoPtr dstFrame; - nsRefPtr srcSurface; - nsRefPtr 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 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 mScaleRequest; - }; - - class DrawRunner : public nsRunnable - { - public: - DrawRunner(ScaleRequest* request); - - NS_IMETHOD Run(); - - private: /* members */ - - nsAutoPtr 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 frame; + ScaleStatus status; + }; + ScaleResult mScaleResult; // We hold on to a bare pointer to a ScaleRequest while it's outstanding so