author | Michael Wu <mwu@mozilla.com> |
Sun, 02 Mar 2014 11:17:26 -0500 | |
changeset 191858 | e09f4b94cf29e637326767738cb7727975707b35 |
parent 191857 | efba9e32aca15069e1df351a988a66f67ee27e4d |
child 191859 | df384c7c679a925ea328b43cc1c1c27b37bd4bff |
push id | 474 |
push user | asasaki@mozilla.com |
push date | Mon, 02 Jun 2014 21:01:02 +0000 |
treeherder | mozilla-release@967f4cf1b31c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | seth |
bugs | 980037 |
milestone | 30.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -244,16 +244,18 @@ public: nsRefPtr<RasterImage> image = weakImage.get(); if (!image) { return false; } bool success = false; if (dstLocked) { + if (DiscardingEnabled()) + dstFrame->SetDiscardable(); success = NS_SUCCEEDED(dstFrame->UnlockImageData()); dstLocked = false; srcData = nullptr; dstData = nullptr; srcSurface = nullptr; dstSurface = nullptr; } @@ -2558,80 +2560,96 @@ RasterImage::ScalingDone(ScaleRequest* r // 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 +bool RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame, gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect &aFill, const nsIntRect &aSubimage, uint32_t aFlags) { imgFrame *frame = aFrame; nsIntRect framerect = frame->GetRect(); gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace; imageSpaceToUserSpace.Invert(); gfx::Size scale = ToSize(imageSpaceToUserSpace.ScaleFactors(true)); nsIntRect subimage = aSubimage; - - if (CanScale(aFilter, scale, aFlags)) { + nsRefPtr<gfxASurface> surf; + + if (CanScale(aFilter, scale, aFlags) && !frame->IsSinglePixel()) { // If scale factor is still the same that we scaled for and // ScaleWorker isn't still working, then we can use pre-downscaled frame. // If scale factor has changed, order new request. // 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. + bool needScaleReq; if (mScaleResult.status == SCALE_DONE && mScaleResult.scale == scale) { - frame = mScaleResult.frame; - userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width, scale.height)); - - // Since we're switching to a scaled image, we need to transform the - // area of the subimage to draw accordingly, since imgFrame::Draw() - // doesn't know about scaled frames. - subimage.ScaleRoundOut(scale.width, scale.height); + // Grab and hold the surface to make sure the OS didn't destroy it + mScaleResult.frame->GetSurface(getter_AddRefs(surf)); + needScaleReq = !surf; + if (surf) { + frame = mScaleResult.frame; + userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width, + scale.height)); + + // Since we're switching to a scaled image, we need to transform the + // area of the subimage to draw accordingly, since imgFrame::Draw() + // doesn't know about scaled frames. + subimage.ScaleRoundOut(scale.width, scale.height); + } + } else { + needScaleReq = !(mScaleResult.status == SCALE_PENDING && + mScaleResult.scale == scale); } // If we're not waiting for exactly this result, and there's only one // instance of this image on this page, ask for a scale. - else if (!(mScaleResult.status == SCALE_PENDING && mScaleResult.scale == scale) && - mLockCount == 1) { - // If we have an oustanding request, signal it to stop (if it can). + if (needScaleReq && mLockCount == 1) { + if (NS_FAILED(frame->LockImageData())) { + frame->UnlockImageData(); + return false; + } + + // If we have an outstanding request, signal it to stop (if it can). if (mScaleRequest) { mScaleRequest->stopped = true; } nsRefPtr<ScaleRunner> runner = new ScaleRunner(this, scale, frame); if (runner->IsOK()) { if (!sScaleWorkerThread) { NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread)); ClearOnShutdown(&sScaleWorkerThread); } sScaleWorkerThread->Dispatch(runner, NS_DISPATCH_NORMAL); } + frame->UnlockImageData(); } } nsIntMargin padding(framerect.y, mSize.width - framerect.XMost(), mSize.height - framerect.YMost(), framerect.x); - frame->Draw(aContext, aFilter, userSpaceToImageSpace, aFill, padding, subimage, - aFlags); + return frame->Draw(aContext, aFilter, userSpaceToImageSpace, + aFill, padding, subimage, aFlags); } //****************************************************************************** /* [noscript] void draw(in gfxContext aContext, * in gfxGraphicsFilter aFilter, * [const] in gfxMatrix aUserSpaceToImageSpace, * [const] in gfxRect aFill, * [const] in nsIntRect aSubimage, @@ -2713,29 +2731,26 @@ RasterImage::Draw(gfxContext *aContext, uint32_t frameIndex = aWhichFrame == FRAME_FIRST ? 0 : GetCurrentImgFrameIndex(); imgFrame* frame = GetDrawableImgFrame(frameIndex); if (!frame) { return NS_OK; // Getting the frame (above) touches the image and kicks off decoding } - nsRefPtr<gfxASurface> surf; - if (!frame->IsSinglePixel()) { - frame->GetSurface(getter_AddRefs(surf)); - if (!surf) { - // The OS threw out some or all of our buffer. Start decoding again. - ForceDiscard(); - WantDecodedFrames(); - return NS_OK; - } + bool drawn = DrawWithPreDownscaleIfNeeded(frame, aContext, aFilter, + aUserSpaceToImageSpace, aFill, + aSubimage, aFlags); + if (!drawn) { + // The OS threw out some or all of our buffer. Start decoding again. + ForceDiscard(); + WantDecodedFrames(); + return NS_OK; } - DrawWithPreDownscaleIfNeeded(frame, aContext, aFilter, aUserSpaceToImageSpace, aFill, aSubimage, aFlags); - if (mDecoded && !mDrawStartTime.IsNull()) { TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime; Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds())); // clear the value of mDrawStartTime mDrawStartTime = TimeStamp(); } return NS_OK;
--- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -540,17 +540,17 @@ private: private: /* members */ nsRefPtr<RasterImage> mImage; }; nsresult FinishedSomeDecoding(eShutdownIntent intent = eShutdownIntent_Done, DecodeRequest* request = nullptr); - void DrawWithPreDownscaleIfNeeded(imgFrame *aFrame, + bool DrawWithPreDownscaleIfNeeded(imgFrame *aFrame, gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect &aFill, const nsIntRect &aSubimage, uint32_t aFlags); nsresult CopyFrame(uint32_t aWhichFrame,
--- a/image/src/imgFrame.cpp +++ b/image/src/imgFrame.cpp @@ -414,22 +414,23 @@ imgFrame::SurfaceWithFormat imgFrame::SurfaceForDrawing(bool aDoPadding, bool aDoPartialDecode, bool aDoTile, const nsIntMargin& aPadding, gfxMatrix& aUserSpaceToImageSpace, gfxRect& aFill, gfxRect& aSubimage, gfxRect& aSourceRect, - gfxRect& aImageRect) + gfxRect& aImageRect, + gfxASurface* aSurface) { IntSize size(int32_t(aImageRect.Width()), int32_t(aImageRect.Height())); if (!aDoPadding && !aDoPartialDecode) { NS_ASSERTION(!mSinglePixel, "This should already have been handled"); - return SurfaceWithFormat(new gfxSurfaceDrawable(ThebesSurface(), ThebesIntSize(size)), mFormat); + return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, ThebesIntSize(size)), mFormat); } gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height); if (aDoTile || mSinglePixel) { // Create a temporary surface. // Give this surface an alpha channel because there are // transparent pixels in the padding or undecoded area @@ -440,17 +441,17 @@ imgFrame::SurfaceForDrawing(bool return SurfaceWithFormat(); // Fill 'available' with whatever we've got gfxContext tmpCtx(surface); tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE); if (mSinglePixel) { tmpCtx.SetDeviceColor(mSinglePixelColor); } else { - tmpCtx.SetSource(ThebesSurface(), gfxPoint(aPadding.left, aPadding.top)); + tmpCtx.SetSource(aSurface, gfxPoint(aPadding.left, aPadding.top)); } tmpCtx.Rectangle(available); tmpCtx.Fill(); return SurfaceWithFormat(new gfxSurfaceDrawable(surface, ThebesIntSize(size)), format); } // Not tiling, and we have a surface, so we can account for @@ -462,62 +463,69 @@ imgFrame::SurfaceForDrawing(bool aFill = imageSpaceToUserSpace.Transform(aSourceRect); aSubimage = aSubimage.Intersect(available) - gfxPoint(aPadding.left, aPadding.top); aUserSpaceToImageSpace.Multiply(gfxMatrix().Translate(-gfxPoint(aPadding.left, aPadding.top))); aSourceRect = aSourceRect - gfxPoint(aPadding.left, aPadding.top); aImageRect = gfxRect(0, 0, mSize.width, mSize.height); gfxIntSize availableSize(mDecoded.width, mDecoded.height); - return SurfaceWithFormat(new gfxSurfaceDrawable(ThebesSurface(), - availableSize), + return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize), mFormat); } -void imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter, +bool imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage, uint32_t aImageFlags) { PROFILER_LABEL("image", "imgFrame::Draw"); NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller"); NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller"); NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!"); bool doPadding = aPadding != nsIntMargin(0,0,0,0); bool doPartialDecode = !ImageComplete(); if (mSinglePixel && !doPadding && !doPartialDecode) { DoSingleColorFastPath(aContext, mSinglePixelColor, aFill); - return; + return true; } gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxRect sourceRect = userSpaceToImageSpace.TransformBounds(aFill); gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom()); gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); gfxRect fill = aFill; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); + nsRefPtr<gfxASurface> surf; + if (!mSinglePixel) { + surf = ThebesSurface(); + if (!surf) + return false; + } + bool doTile = !imageRect.Contains(sourceRect) && !(aImageFlags & imgIContainer::FLAG_CLAMP); SurfaceWithFormat surfaceResult = SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding, userSpaceToImageSpace, fill, subimage, sourceRect, - imageRect); + imageRect, surf); if (surfaceResult.IsValid()) { gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable, userSpaceToImageSpace, subimage, sourceRect, imageRect, fill, surfaceResult.mFormat, aFilter, aImageFlags); } + return true; } // This can be called from any thread, but not simultaneously. nsresult imgFrame::ImageUpdated(const nsIntRect &aUpdateRect) { MutexAutoLock lock(mDirtyMutex); mDecoded.UnionRect(mDecoded, aUpdateRect);
--- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -44,17 +44,17 @@ class imgFrame { public: imgFrame(); ~imgFrame(); nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfxImageFormat aFormat, uint8_t aPaletteDepth = 0); nsresult Optimize(); - void Draw(gfxContext *aContext, GraphicsFilter aFilter, + bool Draw(gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage, uint32_t aImageFlags = imgIContainer::FLAG_NONE); nsresult ImageUpdated(const nsIntRect &aUpdateRect); bool GetIsDirty() const; nsIntRect GetRect() const; @@ -177,17 +177,18 @@ private: // methods SurfaceWithFormat SurfaceForDrawing(bool aDoPadding, bool aDoPartialDecode, bool aDoTile, const nsIntMargin& aPadding, gfxMatrix& aUserSpaceToImageSpace, gfxRect& aFill, gfxRect& aSubimage, gfxRect& aSourceRect, - gfxRect& aImageRect); + gfxRect& aImageRect, + gfxASurface* aSurface); private: // data nsRefPtr<gfxImageSurface> mImageSurface; nsRefPtr<gfxASurface> mOptSurface; #if defined(XP_WIN) nsRefPtr<gfxWindowsSurface> mWinSurface; #elif defined(XP_MACOSX) nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;