Bug 1323912 - Part 2. Pass opacity down to imgIContainer::Draw. r=mstange
☠☠ backed out by 7a3238ae0f8f ☠ ☠
authorcku <cku@mozilla.com>
Tue, 03 Jan 2017 13:53:22 +0800
changeset 375288 c868ab532766e6a98ed771d9477ed745d4c67f98
parent 375287 a446407015581697b803ec2170d2c892787e05c3
child 375289 71c136b30a4d8b02fd17c9c48fedc3f07e9267e4
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1323912
milestone53.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
Bug 1323912 - Part 2. Pass opacity down to imgIContainer::Draw. r=mstange Each concrete class of imgIContainer is able to handle opacity already. All we need to do is pass opacity value to them. MozReview-Commit-ID: EMkLnG3YXA1
dom/canvas/CanvasRenderingContext2D.cpp
image/ClippedImage.cpp
image/ClippedImage.h
image/DynamicImage.cpp
image/FrozenImage.cpp
image/FrozenImage.h
image/ImageWrapper.cpp
image/OrientedImage.cpp
image/OrientedImage.h
image/RasterImage.cpp
image/RasterImage.h
image/VectorImage.cpp
image/imgFrame.cpp
image/imgFrame.h
image/imgIContainer.idl
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
widget/nsBaseDragService.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5095,17 +5095,17 @@ CanvasRenderingContext2D::DrawDirectlyTo
   uint32_t modifiedFlags = aImage.mDrawingFlags | imgIContainer::FLAG_CLAMP;
 
   CSSIntSize sz(scaledImageSize.width, scaledImageSize.height); // XXX hmm is scaledImageSize really in CSS pixels?
   SVGImageContext svgContext(sz, Nothing(), CurrentState().globalAlpha);
 
   auto result = aImage.mImgContainer->
     Draw(context, scaledImageSize,
          ImageRegion::Create(gfxRect(aSrc.x, aSrc.y, aSrc.width, aSrc.height)),
-         aImage.mWhichFrame, SamplingFilter::GOOD, Some(svgContext), modifiedFlags);
+         aImage.mWhichFrame, SamplingFilter::GOOD, Some(svgContext), modifiedFlags, 1.0);
 
   if (result != DrawResult::SUCCESS) {
     NS_WARNING("imgIContainer::Draw failed");
   }
 }
 
 void
 CanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& aOp,
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -93,23 +93,25 @@ private:
 
 class DrawSingleTileCallback : public gfxDrawingCallback
 {
 public:
   DrawSingleTileCallback(ClippedImage* aImage,
                          const nsIntSize& aSize,
                          const Maybe<SVGImageContext>& aSVGContext,
                          uint32_t aWhichFrame,
-                         uint32_t aFlags)
+                         uint32_t aFlags,
+                         float aOpacity)
     : mImage(aImage)
     , mSize(aSize)
     , mSVGContext(aSVGContext)
     , mWhichFrame(aWhichFrame)
     , mFlags(aFlags)
     , mDrawResult(DrawResult::NOT_READY)
+    , mOpacity(aOpacity)
   {
     MOZ_ASSERT(mImage, "Must have an image to clip");
   }
 
   virtual bool operator()(gfxContext* aContext,
                           const gfxRect& aFillRect,
                           const SamplingFilter aSamplingFilter,
                           const gfxMatrix& aTransform)
@@ -117,30 +119,32 @@ public:
     MOZ_ASSERT(aTransform.IsIdentity(),
                "Caller is probably CreateSamplingRestrictedDrawable, "
                "which should not happen");
 
     // Draw the image. |gfxCallbackDrawable| always calls this function with
     // arguments that guarantee we never tile.
     mDrawResult =
       mImage->DrawSingleTile(aContext, mSize, ImageRegion::Create(aFillRect),
-                             mWhichFrame, aSamplingFilter, mSVGContext, mFlags);
+                             mWhichFrame, aSamplingFilter, mSVGContext, mFlags,
+                             mOpacity);
 
     return true;
   }
 
   DrawResult GetDrawResult() { return mDrawResult; }
 
 private:
   RefPtr<ClippedImage>        mImage;
   const nsIntSize               mSize;
   const Maybe<SVGImageContext>& mSVGContext;
   const uint32_t                mWhichFrame;
   const uint32_t                mFlags;
   DrawResult                    mDrawResult;
+  float                         mOpacity;
 };
 
 ClippedImage::ClippedImage(Image* aImage,
                            nsIntRect aClip,
                            const Maybe<nsSize>& aSVGViewportSize)
   : ImageWrapper(aImage)
   , mClip(aClip)
 {
@@ -253,17 +257,17 @@ ClippedImage::GetIntrinsicRatio(nsSize* 
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ClippedImage::GetFrame(uint32_t aWhichFrame,
                        uint32_t aFlags)
 {
   DrawResult result;
   RefPtr<SourceSurface> surface;
-  Tie(result, surface) = GetFrameInternal(mClip.Size(), Nothing(), aWhichFrame, aFlags);
+  Tie(result, surface) = GetFrameInternal(mClip.Size(), Nothing(), aWhichFrame, aFlags, 1.0);
   return surface.forget();
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ClippedImage::GetFrameAtSize(const IntSize& aSize,
                              uint32_t aWhichFrame,
                              uint32_t aFlags)
 {
@@ -271,17 +275,18 @@ ClippedImage::GetFrameAtSize(const IntSi
   // but right now we just fall back to the intrinsic size.
   return GetFrame(aWhichFrame, aFlags);
 }
 
 Pair<DrawResult, RefPtr<SourceSurface>>
 ClippedImage::GetFrameInternal(const nsIntSize& aSize,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aWhichFrame,
-                               uint32_t aFlags)
+                               uint32_t aFlags,
+                               float aOpacity)
 {
   if (!ShouldClip()) {
     RefPtr<SourceSurface> surface = InnerImage()->GetFrame(aWhichFrame, aFlags);
     return MakePair(surface ? DrawResult::SUCCESS : DrawResult::NOT_READY,
                     Move(surface));
   }
 
   float frameToDraw = InnerImage()->GetFrameIndex(aWhichFrame);
@@ -297,17 +302,18 @@ ClippedImage::GetFrameInternal(const nsI
       return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
     }
 
     RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(target);
     MOZ_ASSERT(ctx); // already checked the draw target above
 
     // Create our callback.
     RefPtr<DrawSingleTileCallback> drawTileCallback =
-      new DrawSingleTileCallback(this, aSize, aSVGContext, aWhichFrame, aFlags);
+      new DrawSingleTileCallback(this, aSize, aSVGContext, aWhichFrame, aFlags,
+                                 aOpacity);
     RefPtr<gfxDrawable> drawable =
       new gfxCallbackDrawable(drawTileCallback, aSize);
 
     // Actually draw. The callback will end up invoking DrawSingleTile.
     gfxUtils::DrawPixelSnapped(ctx, drawable, aSize,
                                ImageRegion::Create(aSize),
                                SurfaceFormat::B8G8R8A8,
                                SamplingFilter::LINEAR,
@@ -366,60 +372,63 @@ MustCreateSurface(gfxContext* aContext,
 
 NS_IMETHODIMP_(DrawResult)
 ClippedImage::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
                    const ImageRegion& aRegion,
                    uint32_t aWhichFrame,
                    SamplingFilter aSamplingFilter,
                    const Maybe<SVGImageContext>& aSVGContext,
-                   uint32_t aFlags)
+                   uint32_t aFlags,
+                   float aOpacity)
 {
   if (!ShouldClip()) {
     return InnerImage()->Draw(aContext, aSize, aRegion, aWhichFrame,
-                              aSamplingFilter, aSVGContext, aFlags);
+                              aSamplingFilter, aSVGContext, aFlags, aOpacity);
   }
 
   // Check for tiling. If we need to tile then we need to create a
   // gfxCallbackDrawable to handle drawing for us.
   if (MustCreateSurface(aContext, aSize, aRegion, aFlags)) {
     // Create a temporary surface containing a single tile of this image.
     // GetFrame will call DrawSingleTile internally.
     DrawResult result;
     RefPtr<SourceSurface> surface;
     Tie(result, surface) =
-      GetFrameInternal(aSize, aSVGContext, aWhichFrame, aFlags);
+      GetFrameInternal(aSize, aSVGContext, aWhichFrame, aFlags, aOpacity);
     if (!surface) {
       MOZ_ASSERT(result != DrawResult::SUCCESS);
       return result;
     }
 
     // Create a drawable from that surface.
     RefPtr<gfxSurfaceDrawable> drawable =
       new gfxSurfaceDrawable(surface, aSize);
 
     // Draw.
     gfxUtils::DrawPixelSnapped(aContext, drawable, aSize, aRegion,
-                               SurfaceFormat::B8G8R8A8, aSamplingFilter);
+                               SurfaceFormat::B8G8R8A8, aSamplingFilter,
+                               aOpacity);
 
     return result;
   }
 
   return DrawSingleTile(aContext, aSize, aRegion, aWhichFrame,
-                        aSamplingFilter, aSVGContext, aFlags);
+                        aSamplingFilter, aSVGContext, aFlags, aOpacity);
 }
 
 DrawResult
 ClippedImage::DrawSingleTile(gfxContext* aContext,
                              const nsIntSize& aSize,
                              const ImageRegion& aRegion,
                              uint32_t aWhichFrame,
                              SamplingFilter aSamplingFilter,
                              const Maybe<SVGImageContext>& aSVGContext,
-                             uint32_t aFlags)
+                             uint32_t aFlags,
+                             float aOpacity)
 {
   MOZ_ASSERT(!MustCreateSurface(aContext, aSize, aRegion, aFlags),
              "Shouldn't need to create a surface");
 
   gfxRect clip(mClip.x, mClip.y, mClip.width, mClip.height);
   nsIntSize size(aSize), innerSize(aSize);
   bool needScale = false;
   if (mSVGViewportSize && !mSVGViewportSize->IsEmpty()) {
@@ -465,17 +474,17 @@ ClippedImage::DrawSingleTile(gfxContext*
 
     return SVGImageContext(vSize,
                            aOldContext.GetPreserveAspectRatio());
   };
 
   return InnerImage()->Draw(aContext, size, region,
                             aWhichFrame, aSamplingFilter,
                             aSVGContext.map(unclipViewport),
-                            aFlags);
+                            aFlags, aOpacity);
 }
 
 NS_IMETHODIMP
 ClippedImage::RequestDiscard()
 {
   // We're very aggressive about discarding.
   mCachedSurface = nullptr;
 
--- a/image/ClippedImage.h
+++ b/image/ClippedImage.h
@@ -48,17 +48,18 @@ public:
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                gfx::SamplingFilter aSamplingFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
-                               uint32_t aFlags) override;
+                               uint32_t aFlags,
+                               float aOpacity) override;
   NS_IMETHOD RequestDiscard() override;
   NS_IMETHOD_(Orientation) GetOrientation() override;
   NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect)
     override;
   nsIntSize OptimalImageSizeForDest(const gfxSize& aDest,
                                     uint32_t aWhichFrame,
                                     gfx::SamplingFilter aSamplingFilter,
                                     uint32_t aFlags) override;
@@ -69,25 +70,27 @@ protected:
 
   virtual ~ClippedImage();
 
 private:
   Pair<DrawResult, RefPtr<SourceSurface>>
     GetFrameInternal(const nsIntSize& aSize,
                      const Maybe<SVGImageContext>& aSVGContext,
                      uint32_t aWhichFrame,
-                     uint32_t aFlags);
+                     uint32_t aFlags,
+                     float aOpacity);
   bool ShouldClip();
   DrawResult DrawSingleTile(gfxContext* aContext,
                             const nsIntSize& aSize,
                             const ImageRegion& aRegion,
                             uint32_t aWhichFrame,
                             gfx::SamplingFilter aSamplingFilter,
                             const Maybe<SVGImageContext>& aSVGContext,
-                            uint32_t aFlags);
+                            uint32_t aFlags,
+                            float aOpacity);
 
   // If we are forced to draw a temporary surface, we cache it here.
   UniquePtr<ClippedImageCachedSurface> mCachedSurface;
 
   nsIntRect        mClip;            // The region to clip to.
   Maybe<bool>      mShouldClip;      // Memoized ShouldClip() if present.
   Maybe<nsIntSize> mSVGViewportSize; // If we're clipping a VectorImage, this
                                      // is the size of viewport of that image.
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -184,17 +184,18 @@ DynamicImage::GetFrameAtSize(const IntSi
     gfxWarning() <<
       "DynamicImage::GetFrame failed in CreateOffscreenContentDrawTarget";
     return nullptr;
   }
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
   MOZ_ASSERT(context); // already checked the draw target above
 
   auto result = Draw(context, aSize, ImageRegion::Create(aSize),
-                     aWhichFrame, SamplingFilter::POINT, Nothing(), aFlags);
+                     aWhichFrame, SamplingFilter::POINT, Nothing(), aFlags,
+                     1.0);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
 NS_IMETHODIMP_(bool)
 DynamicImage::WillDrawOpaqueNow()
 {
   return false;
@@ -214,39 +215,42 @@ DynamicImage::GetImageContainer(LayerMan
 
 NS_IMETHODIMP_(DrawResult)
 DynamicImage::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
                    const ImageRegion& aRegion,
                    uint32_t aWhichFrame,
                    SamplingFilter aSamplingFilter,
                    const Maybe<SVGImageContext>& aSVGContext,
-                   uint32_t aFlags)
+                   uint32_t aFlags,
+                   float aOpacity)
 {
   MOZ_ASSERT(!aSize.IsEmpty(), "Unexpected empty size");
 
   IntSize drawableSize(mDrawable->Size());
 
   if (aSize == drawableSize) {
     gfxUtils::DrawPixelSnapped(aContext, mDrawable, drawableSize, aRegion,
-                               SurfaceFormat::B8G8R8A8, aSamplingFilter);
+                               SurfaceFormat::B8G8R8A8, aSamplingFilter,
+                               aOpacity);
     return DrawResult::SUCCESS;
   }
 
   gfxSize scale(double(aSize.width) / drawableSize.width,
                 double(aSize.height) / drawableSize.height);
 
   ImageRegion region(aRegion);
   region.Scale(1.0 / scale.width, 1.0 / scale.height);
 
   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
   aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
 
   gfxUtils::DrawPixelSnapped(aContext, mDrawable, drawableSize, region,
-                             SurfaceFormat::B8G8R8A8, aSamplingFilter);
+                             SurfaceFormat::B8G8R8A8, aSamplingFilter,
+                             aOpacity);
   return DrawResult::SUCCESS;
 }
 
 NS_IMETHODIMP
 DynamicImage::StartDecoding(uint32_t aFlags)
 {
   return NS_OK;
 }
--- a/image/FrozenImage.cpp
+++ b/image/FrozenImage.cpp
@@ -73,20 +73,21 @@ FrozenImage::GetImageContainer(layers::L
 
 NS_IMETHODIMP_(DrawResult)
 FrozenImage::Draw(gfxContext* aContext,
                   const nsIntSize& aSize,
                   const ImageRegion& aRegion,
                   uint32_t /* aWhichFrame - ignored */,
                   SamplingFilter aSamplingFilter,
                   const Maybe<SVGImageContext>& aSVGContext,
-                  uint32_t aFlags)
+                  uint32_t aFlags,
+                  float aOpacity)
 {
   return InnerImage()->Draw(aContext, aSize, aRegion, FRAME_FIRST,
-                            aSamplingFilter, aSVGContext, aFlags);
+                            aSamplingFilter, aSVGContext, aFlags, aOpacity);
 }
 
 NS_IMETHODIMP_(void)
 FrozenImage::RequestRefresh(const TimeStamp& aTime)
 {
   // Do nothing.
 }
 
--- a/image/FrozenImage.h
+++ b/image/FrozenImage.h
@@ -47,17 +47,18 @@ public:
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                gfx::SamplingFilter aSamplingFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
-                               uint32_t aFlags) override;
+                               uint32_t aFlags,
+                               float aOpacity) override;
   NS_IMETHOD_(void) RequestRefresh(const TimeStamp& aTime) override;
   NS_IMETHOD GetAnimationMode(uint16_t* aAnimationMode) override;
   NS_IMETHOD SetAnimationMode(uint16_t aAnimationMode) override;
   NS_IMETHOD ResetAnimation() override;
   NS_IMETHOD_(float) GetFrameIndex(uint32_t aWhichFrame) override;
 
 protected:
   explicit FrozenImage(Image* aImage) : ImageWrapper(aImage) { }
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -204,20 +204,21 @@ ImageWrapper::GetImageContainer(LayerMan
 
 NS_IMETHODIMP_(DrawResult)
 ImageWrapper::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
                    const ImageRegion& aRegion,
                    uint32_t aWhichFrame,
                    SamplingFilter aSamplingFilter,
                    const Maybe<SVGImageContext>& aSVGContext,
-                   uint32_t aFlags)
+                   uint32_t aFlags,
+                   float aOpacity)
 {
   return mInnerImage->Draw(aContext, aSize, aRegion, aWhichFrame,
-                           aSamplingFilter, aSVGContext, aFlags);
+                           aSamplingFilter, aSVGContext, aFlags, aOpacity);
 }
 
 NS_IMETHODIMP
 ImageWrapper::StartDecoding(uint32_t aFlags)
 {
   return mInnerImage->StartDecoding(aFlags);
 }
 
--- a/image/OrientedImage.cpp
+++ b/image/OrientedImage.cpp
@@ -258,22 +258,23 @@ OrientedImage::OrientationMatrix(const n
 
 NS_IMETHODIMP_(DrawResult)
 OrientedImage::Draw(gfxContext* aContext,
                     const nsIntSize& aSize,
                     const ImageRegion& aRegion,
                     uint32_t aWhichFrame,
                     SamplingFilter aSamplingFilter,
                     const Maybe<SVGImageContext>& aSVGContext,
-                    uint32_t aFlags)
+                    uint32_t aFlags,
+                    float aOpacity)
 {
   if (mOrientation.IsIdentity()) {
     return InnerImage()->Draw(aContext, aSize, aRegion,
                               aWhichFrame, aSamplingFilter,
-                              aSVGContext, aFlags);
+                              aSVGContext, aFlags, aOpacity);
   }
 
   // Update the image size to match the image's coordinate system. (This could
   // be done using TransformBounds but since it's only a size a swap is enough.)
   nsIntSize size(aSize);
   if (mOrientation.SwapsWidthAndHeight()) {
     swap(size.width, size.height);
   }
@@ -295,18 +296,20 @@ OrientedImage::Draw(gfxContext* aContext
     CSSIntSize viewportSize(aOldContext.GetViewportSize());
     if (mOrientation.SwapsWidthAndHeight()) {
       swap(viewportSize.width, viewportSize.height);
     }
     return SVGImageContext(viewportSize,
                            aOldContext.GetPreserveAspectRatio());
   };
 
-  return InnerImage()->Draw(aContext, size, region, aWhichFrame, aSamplingFilter,
-                            aSVGContext.map(orientViewport), aFlags);
+  return InnerImage()->Draw(aContext, size, region, aWhichFrame,
+                            aSamplingFilter,
+                            aSVGContext.map(orientViewport), aFlags,
+                            aOpacity);
 }
 
 nsIntSize
 OrientedImage::OptimalImageSizeForDest(const gfxSize& aDest,
                                        uint32_t aWhichFrame,
                                        SamplingFilter aSamplingFilter,
                                        uint32_t aFlags)
 {
--- a/image/OrientedImage.h
+++ b/image/OrientedImage.h
@@ -44,17 +44,18 @@ public:
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                gfx::SamplingFilter aSamplingFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
-                               uint32_t aFlags) override;
+                               uint32_t aFlags,
+                               float aOpacity) override;
   NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(
                                            const nsIntRect& aRect) override;
   nsIntSize OptimalImageSizeForDest(const gfxSize& aDest,
                                     uint32_t aWhichFrame,
                                     gfx::SamplingFilter aSamplingFilter,
                                     uint32_t aFlags) override;
 
 protected:
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1306,17 +1306,18 @@ RasterImage::CanDownscaleDuringDecode(co
 }
 
 DrawResult
 RasterImage::DrawInternal(DrawableSurface&& aSurface,
                           gfxContext* aContext,
                           const IntSize& aSize,
                           const ImageRegion& aRegion,
                           SamplingFilter aSamplingFilter,
-                          uint32_t aFlags)
+                          uint32_t aFlags,
+                          float aOpacity)
 {
   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
   ImageRegion region(aRegion);
   bool frameIsFinished = aSurface->IsFinished();
 
   // By now we may have a frame with the requested size. If not, we need to
   // adjust the drawing parameters accordingly.
   IntSize finalSize = aSurface->GetImageSize();
@@ -1325,17 +1326,17 @@ RasterImage::DrawInternal(DrawableSurfac
     gfx::Size scale(double(aSize.width) / finalSize.width,
                     double(aSize.height) / finalSize.height);
     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
     region.Scale(1.0 / scale.width, 1.0 / scale.height);
 
     couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
   }
 
-  if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags)) {
+  if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags, aOpacity)) {
     RecoverFromInvalidFrames(aSize, aFlags);
     return DrawResult::TEMPORARY_ERROR;
   }
   if (!frameIsFinished) {
     return DrawResult::INCOMPLETE;
   }
   if (couldRedecodeForBetterFrame) {
     return DrawResult::WRONG_SIZE;
@@ -1346,17 +1347,18 @@ RasterImage::DrawInternal(DrawableSurfac
 //******************************************************************************
 NS_IMETHODIMP_(DrawResult)
 RasterImage::Draw(gfxContext* aContext,
                   const IntSize& aSize,
                   const ImageRegion& aRegion,
                   uint32_t aWhichFrame,
                   SamplingFilter aSamplingFilter,
                   const Maybe<SVGImageContext>& /*aSVGContext - ignored*/,
-                  uint32_t aFlags)
+                  uint32_t aFlags,
+                  float aOpacity)
 {
   if (aWhichFrame > FRAME_MAX_VALUE) {
     return DrawResult::BAD_ARGS;
   }
 
   if (mError) {
     return DrawResult::BAD_IMAGE;
   }
@@ -1392,17 +1394,17 @@ RasterImage::Draw(gfxContext* aContext,
     }
     return DrawResult::NOT_READY;
   }
 
   bool shouldRecordTelemetry = !mDrawStartTime.IsNull() &&
                                surface->IsFinished();
 
   auto result = DrawInternal(Move(surface), aContext, aSize,
-                             aRegion, aSamplingFilter, flags);
+                             aRegion, aSamplingFilter, flags, aOpacity);
 
   if (shouldRecordTelemetry) {
       TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY,
                             int32_t(drawLatency.ToMicroseconds()));
       mDrawStartTime = TimeStamp();
   }
 
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -297,17 +297,18 @@ private:
                                    uint32_t aFlags,
                                    PlaybackType aPlaybackType);
 
   DrawResult DrawInternal(DrawableSurface&& aFrameRef,
                           gfxContext* aContext,
                           const nsIntSize& aSize,
                           const ImageRegion& aRegion,
                           gfx::SamplingFilter aSamplingFilter,
-                          uint32_t aFlags);
+                          uint32_t aFlags,
+                          float aOpacity);
 
   Pair<DrawResult, RefPtr<gfx::SourceSurface>>
     GetFrameInternal(const gfx::IntSize& aSize,
                      uint32_t aWhichFrame,
                      uint32_t aFlags);
 
   Pair<DrawResult, RefPtr<layers::Image>>
     GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags);
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -745,17 +745,18 @@ VectorImage::GetFrameAtSize(const IntSiz
     NS_ERROR("Could not create a DrawTarget");
     return nullptr;
   }
 
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
   MOZ_ASSERT(context); // already checked the draw target above
 
   auto result = Draw(context, aSize, ImageRegion::Create(aSize),
-                     aWhichFrame, SamplingFilter::POINT, Nothing(), aFlags);
+                     aWhichFrame, SamplingFilter::POINT, Nothing(), aFlags,
+                     1.0);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
 NS_IMETHODIMP_(bool)
 VectorImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   return false;
@@ -771,26 +772,27 @@ VectorImage::GetImageContainer(LayerMana
 struct SVGDrawingParameters
 {
   SVGDrawingParameters(gfxContext* aContext,
                        const nsIntSize& aSize,
                        const ImageRegion& aRegion,
                        SamplingFilter aSamplingFilter,
                        const Maybe<SVGImageContext>& aSVGContext,
                        float aAnimationTime,
-                       uint32_t aFlags)
+                       uint32_t aFlags,
+                       float aOpacity)
     : context(aContext)
     , size(aSize.width, aSize.height)
     , region(aRegion)
     , samplingFilter(aSamplingFilter)
     , svgContext(aSVGContext)
     , viewportSize(aSize)
     , animationTime(aAnimationTime)
     , flags(aFlags)
-    , opacity(aSVGContext ? aSVGContext->GetGlobalOpacity() : 1.0)
+    , opacity(aSVGContext ? aSVGContext->GetGlobalOpacity() : aOpacity)
   {
     if (aSVGContext) {
       CSSIntSize sz = aSVGContext->GetViewportSize();
       viewportSize = nsIntSize(sz.width, sz.height); // XXX losing unit
     }
   }
 
   gfxContext*                   context;
@@ -807,17 +809,18 @@ struct SVGDrawingParameters
 //******************************************************************************
 NS_IMETHODIMP_(DrawResult)
 VectorImage::Draw(gfxContext* aContext,
                   const nsIntSize& aSize,
                   const ImageRegion& aRegion,
                   uint32_t aWhichFrame,
                   SamplingFilter aSamplingFilter,
                   const Maybe<SVGImageContext>& aSVGContext,
-                  uint32_t aFlags)
+                  uint32_t aFlags,
+                  float aOpacity)
 {
   if (aWhichFrame > FRAME_MAX_VALUE) {
     return DrawResult::BAD_ARGS;
   }
 
   if (!aContext) {
     return DrawResult::BAD_ARGS;
   }
@@ -862,17 +865,17 @@ VectorImage::Draw(gfxContext* aContext,
   float animTime =
     (aWhichFrame == FRAME_FIRST) ? 0.0f
                                  : mSVGDocumentWrapper->GetCurrentTime();
   AutoSVGRenderingState autoSVGState(svgContext, animTime,
                                      mSVGDocumentWrapper->GetRootSVGElem());
 
 
   SVGDrawingParameters params(aContext, aSize, aRegion, aSamplingFilter,
-                              svgContext, animTime, aFlags);
+                              svgContext, animTime, aFlags, aOpacity);
 
   // If we have an prerasterized version of this image that matches the
   // drawing parameters, use that.
   RefPtr<gfxDrawable> svgDrawable = LookupCachedSurface(params);
   if (svgDrawable) {
     Show(svgDrawable, params);
     return DrawResult::SUCCESS;
   }
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -534,17 +534,18 @@ imgFrame::SurfaceForDrawing(bool        
   aRegion = aRegion.Intersect(available);
   IntSize availableSize(mDecoded.width, mDecoded.height);
 
   return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize),
                            mFormat);
 }
 
 bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
-                    SamplingFilter aSamplingFilter, uint32_t aImageFlags)
+                    SamplingFilter aSamplingFilter, uint32_t aImageFlags,
+                    float aOpacity)
 {
   PROFILER_LABEL("imgFrame", "Draw",
     js::ProfileEntry::Category::GRAPHICS);
 
   MOZ_ASSERT(NS_IsMainThread());
   NS_ASSERTION(!aRegion.Rect().IsEmpty(), "Drawing empty region!");
   NS_ASSERTION(!aRegion.IsRestricted() ||
                !aRegion.Rect().Intersect(aRegion.Restriction()).IsEmpty(),
@@ -576,17 +577,17 @@ bool imgFrame::Draw(gfxContext* aContext
 
   ImageRegion region(aRegion);
   SurfaceWithFormat surfaceResult =
     SurfaceForDrawing(doPartialDecode, doTile, region, surf);
 
   if (surfaceResult.IsValid()) {
     gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable,
                                imageRect.Size(), region, surfaceResult.mFormat,
-                               aSamplingFilter, aImageFlags);
+                               aSamplingFilter, aImageFlags, aOpacity);
   }
   return true;
 }
 
 nsresult
 imgFrame::ImageUpdated(const nsIntRect& aUpdateRect)
 {
   MonitorAutoLock lock(mMonitor);
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -252,17 +252,18 @@ public:
    * volatile buffer to be freed.
    *
    * It is an error to call this without already holding a RawAccessFrameRef to
    * this imgFrame.
    */
   void SetRawAccessOnly();
 
   bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
-            SamplingFilter aSamplingFilter, uint32_t aImageFlags);
+            SamplingFilter aSamplingFilter, uint32_t aImageFlags,
+            float aOpacity);
 
   nsresult ImageUpdated(const nsIntRect& aUpdateRect);
 
   /**
    * Mark this imgFrame as completely decoded, and set final options.
    *
    * You must always call either Finish() or Abort() before releasing the last
    * RawAccessFrameRef pointing to an imgFrame.
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -402,17 +402,18 @@ interface imgIContainer : nsISupports
    */
   [noscript, notxpcom] DrawResult
   draw(in gfxContext aContext,
        [const] in nsIntSize aSize,
        [const] in ImageRegion aRegion,
        in uint32_t aWhichFrame,
        in SamplingFilter aSamplingFilter,
        [const] in MaybeSVGImageContext aSVGContext,
-       in uint32_t aFlags);
+       in uint32_t aFlags,
+       in float aOpacity);
 
   /*
    * Ensures that an image is decoding. Calling this function guarantees that
    * the image will at some point fire off decode notifications. Images that
    * can be decoded "quickly" according to some heuristic will be decoded
    * synchronously.
    *
    * @param aFlags Flags of the FLAG_* variety. Only FLAG_ASYNC_NOTIFY
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6457,17 +6457,18 @@ DrawImageInternal(gfxContext&           
                   imgIContainer*         aImage,
                   const SamplingFilter   aSamplingFilter,
                   const nsRect&          aDest,
                   const nsRect&          aFill,
                   const nsPoint&         aAnchor,
                   const nsRect&          aDirty,
                   const SVGImageContext* aSVGContext,
                   uint32_t               aImageFlags,
-                  ExtendMode             aExtendMode = ExtendMode::CLAMP)
+                  ExtendMode             aExtendMode = ExtendMode::CLAMP,
+                  float                  aOpacity = 1.0)
 {
   DrawResult result = DrawResult::SUCCESS;
 
   aImageFlags |= imgIContainer::FLAG_ASYNC_NOTIFY;
 
   if (aPresContext->Type() == nsPresContext::eContext_Print) {
     // We want vector images to be passed on as vector commands, not a raster
     // image.
@@ -6498,17 +6499,17 @@ DrawImageInternal(gfxContext&           
     Maybe<SVGImageContext> svgContext = ToMaybe(aSVGContext);
     if (!svgContext) {
       // Use the default viewport.
       svgContext = Some(SVGImageContext(params.svgViewportSize, Nothing()));
     }
 
     result = aImage->Draw(destCtx, params.size, params.region,
                           imgIContainer::FRAME_CURRENT, aSamplingFilter,
-                          svgContext, aImageFlags);
+                          svgContext, aImageFlags, aOpacity);
 
   }
 
   return result;
 }
 
 /* static */ DrawResult
 nsLayoutUtils::DrawSingleUnscaledImage(gfxContext&          aContext,
@@ -6670,39 +6671,42 @@ nsLayoutUtils::DrawBackgroundImage(gfxCo
                                    const CSSIntSize&   aImageSize,
                                    SamplingFilter      aSamplingFilter,
                                    const nsRect&       aDest,
                                    const nsRect&       aFill,
                                    const nsSize&       aRepeatSize,
                                    const nsPoint&      aAnchor,
                                    const nsRect&       aDirty,
                                    uint32_t            aImageFlags,
-                                   ExtendMode          aExtendMode)
+                                   ExtendMode          aExtendMode,
+                                   float               aOpacity)
 {
   PROFILER_LABEL("layout", "nsLayoutUtils::DrawBackgroundImage",
                  js::ProfileEntry::Category::GRAPHICS);
 
   SVGImageContext svgContext(aImageSize, Nothing());
 
   /* Fast path when there is no need for image spacing */
   if (aRepeatSize.width == aDest.width && aRepeatSize.height == aDest.height) {
     return DrawImageInternal(aContext, aPresContext, aImage,
                              aSamplingFilter, aDest, aFill, aAnchor,
-                             aDirty, &svgContext, aImageFlags, aExtendMode);
+                             aDirty, &svgContext, aImageFlags, aExtendMode,
+                             aOpacity);
   }
 
   nsPoint firstTilePos = aDest.TopLeft() +
                          nsPoint(NSToIntFloor(float(aFill.x - aDest.x) / aRepeatSize.width) * aRepeatSize.width,
                                  NSToIntFloor(float(aFill.y - aDest.y) / aRepeatSize.height) * aRepeatSize.height);
   for (int32_t i = firstTilePos.x; i < aFill.XMost(); i += aRepeatSize.width) {
     for (int32_t j = firstTilePos.y; j < aFill.YMost(); j += aRepeatSize.height) {
       nsRect dest(i, j, aDest.width, aDest.height);
       DrawResult result = DrawImageInternal(aContext, aPresContext, aImage, aSamplingFilter,
                                             dest, dest, aAnchor, aDirty, &svgContext,
-                                            aImageFlags, ExtendMode::CLAMP);
+                                            aImageFlags, ExtendMode::CLAMP,
+                                            aOpacity);
       if (result != DrawResult::SUCCESS) {
         return result;
       }
     }
   }
 
   return DrawResult::SUCCESS;
 }
@@ -6711,21 +6715,23 @@ nsLayoutUtils::DrawBackgroundImage(gfxCo
 nsLayoutUtils::DrawImage(gfxContext&         aContext,
                          nsPresContext*      aPresContext,
                          imgIContainer*      aImage,
                          const SamplingFilter aSamplingFilter,
                          const nsRect&       aDest,
                          const nsRect&       aFill,
                          const nsPoint&      aAnchor,
                          const nsRect&       aDirty,
-                         uint32_t            aImageFlags)
+                         uint32_t            aImageFlags,
+                         float               aOpacity)
 {
   return DrawImageInternal(aContext, aPresContext, aImage,
                            aSamplingFilter, aDest, aFill, aAnchor,
-                           aDirty, nullptr, aImageFlags);
+                           aDirty, nullptr, aImageFlags, ExtendMode::CLAMP,
+                           aOpacity);
 }
 
 /* static */ nsRect
 nsLayoutUtils::GetWholeImageDestination(const nsSize& aWholeImageSize,
                                         const nsRect& aImageSourceArea,
                                         const nsRect& aDestArea)
 {
   double scaleX = double(aDestArea.width)/aImageSourceArea.width;
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1760,17 +1760,18 @@ public:
                                         const CSSIntSize&   aImageSize,
                                         SamplingFilter      aSamplingFilter,
                                         const nsRect&       aDest,
                                         const nsRect&       aFill,
                                         const nsSize&       aRepeatSize,
                                         const nsPoint&      aAnchor,
                                         const nsRect&       aDirty,
                                         uint32_t            aImageFlags,
-                                        ExtendMode          aExtendMode);
+                                        ExtendMode          aExtendMode,
+                                        float               aOpacity);
 
   /**
    * Draw an image.
    * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
    *   @param aRenderingContext Where to draw the image, set up with an
    *                            appropriate scale and transform for drawing in
    *                            app units.
    *   @param aImage            The image.
@@ -1785,17 +1786,18 @@ public:
   static DrawResult DrawImage(gfxContext&         aContext,
                               nsPresContext*      aPresContext,
                               imgIContainer*      aImage,
                               const SamplingFilter aSamplingFilter,
                               const nsRect&       aDest,
                               const nsRect&       aFill,
                               const nsPoint&      aAnchor,
                               const nsRect&       aDirty,
-                              uint32_t            aImageFlags);
+                              uint32_t            aImageFlags,
+                              float               aOpacity = 1.0);
 
   static inline void InitDashPattern(StrokeOptions& aStrokeOptions,
                                      uint8_t aBorderStyle) {
     if (aBorderStyle == NS_STYLE_BORDER_STYLE_DOTTED) {
       static Float dot[] = { 1.f, 1.f };
       aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dot);
       aStrokeOptions.mDashPattern = dot;
     } else if (aBorderStyle == NS_STYLE_BORDER_STYLE_DASHED) {
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1773,41 +1773,45 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
 
 /* static */
 nsCSSRendering::PaintBGParams
 nsCSSRendering::PaintBGParams::ForAllLayers(nsPresContext& aPresCtx,
                                             nsRenderingContext& aRenderingCtx,
                                             const nsRect& aDirtyRect,
                                             const nsRect& aBorderArea,
                                             nsIFrame *aFrame,
-                                            uint32_t aPaintFlags)
+                                            uint32_t aPaintFlags,
+                                            float aOpacity)
 {
   MOZ_ASSERT(aFrame);
 
-  PaintBGParams result(aPresCtx, aRenderingCtx, aDirtyRect, aBorderArea, aFrame,
-    aPaintFlags, -1, CompositionOp::OP_OVER);
+  PaintBGParams result(aPresCtx, aRenderingCtx, aDirtyRect, aBorderArea,
+                       aFrame, aPaintFlags, -1, CompositionOp::OP_OVER,
+                       aOpacity);
 
   return result;
 }
 
 /* static */
 nsCSSRendering::PaintBGParams
 nsCSSRendering::PaintBGParams::ForSingleLayer(nsPresContext& aPresCtx,
                                               nsRenderingContext& aRenderingCtx,
                                               const nsRect& aDirtyRect,
                                               const nsRect& aBorderArea,
                                               nsIFrame *aFrame,
                                               uint32_t aPaintFlags,
                                               int32_t aLayer,
-                                              CompositionOp aCompositionOp)
+                                              CompositionOp aCompositionOp,
+                                              float aOpacity)
 {
   MOZ_ASSERT(aFrame && (aLayer != -1));
 
-  PaintBGParams result(aPresCtx, aRenderingCtx, aDirtyRect, aBorderArea, aFrame,
-    aPaintFlags, aLayer, aCompositionOp);
+  PaintBGParams result(aPresCtx, aRenderingCtx, aDirtyRect, aBorderArea,
+                       aFrame, aPaintFlags, aLayer, aCompositionOp,
+                       aOpacity);
 
   return result;
 }
 
 DrawResult
 nsCSSRendering::PaintStyleImageLayer(const PaintBGParams& aParams)
 {
   PROFILER_LABEL("nsCSSRendering", "PaintBackground",
@@ -3448,17 +3452,17 @@ nsCSSRendering::PaintStyleImageLayerWith
           }
 
           result &=
             state.mImageRenderer.DrawLayer(&aParams.presCtx,
                                            aParams.renderingCtx,
                                            state.mDestArea, state.mFillArea,
                                            state.mAnchor + paintBorderArea.TopLeft(),
                                            clipState.mDirtyRect,
-                                           state.mRepeatSize);
+                                           state.mRepeatSize, aParams.opacity);
 
           if (co != CompositionOp::OP_OVER) {
             ctx->SetOp(CompositionOp::OP_OVER);
           }
         }
       }
     }
   }
@@ -5640,17 +5644,18 @@ RGBALuminanceOperation(uint8_t *aData,
 DrawResult
 nsImageRenderer::Draw(nsPresContext*       aPresContext,
                       nsRenderingContext&  aRenderingContext,
                       const nsRect&        aDirtyRect,
                       const nsRect&        aDest,
                       const nsRect&        aFill,
                       const nsPoint&       aAnchor,
                       const nsSize&        aRepeatSize,
-                      const CSSIntRect&    aSrc)
+                      const CSSIntRect&    aSrc,
+                      float                aOpacity)
 {
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return DrawResult::TEMPORARY_ERROR;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
     return DrawResult::SUCCESS;
@@ -5691,17 +5696,17 @@ nsImageRenderer::Draw(nsPresContext*    
       result =
         nsLayoutUtils::DrawBackgroundImage(*ctx,
                                            aPresContext,
                                            mImageContainer, imageSize,
                                            samplingFilter,
                                            aDest, aFill, aRepeatSize,
                                            aAnchor, aDirtyRect,
                                            ConvertImageRendererToDrawFlags(mFlags),
-                                           mExtendMode);
+                                           mExtendMode, aOpacity);
       break;
     }
     case eStyleImageType_Gradient:
     {
       nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
                                     mGradientData, aDirtyRect,
                                     aDest, aFill, aRepeatSize, aSrc, mSize);
       break;
@@ -5715,17 +5720,18 @@ nsImageRenderer::Draw(nsPresContext*    
         return DrawResult::TEMPORARY_ERROR;
       }
 
       nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
       result =
         nsLayoutUtils::DrawImage(*ctx,
                                  aPresContext, image,
                                  samplingFilter, aDest, aFill, aAnchor, aDirtyRect,
-                                 ConvertImageRendererToDrawFlags(mFlags));
+                                 ConvertImageRendererToDrawFlags(mFlags),
+                                 aOpacity);
       break;
     }
     case eStyleImageType_Null:
     default:
       break;
   }
 
   if (!tmpDTRect.IsEmpty()) {
@@ -5787,32 +5793,34 @@ nsImageRenderer::DrawableForElement(cons
 
 DrawResult
 nsImageRenderer::DrawLayer(nsPresContext*       aPresContext,
                            nsRenderingContext&  aRenderingContext,
                            const nsRect&        aDest,
                            const nsRect&        aFill,
                            const nsPoint&       aAnchor,
                            const nsRect&        aDirty,
-                           const nsSize&        aRepeatSize)
+                           const nsSize&        aRepeatSize,
+                           float                aOpacity)
 {
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return DrawResult::TEMPORARY_ERROR;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
     return DrawResult::SUCCESS;
   }
 
   return Draw(aPresContext, aRenderingContext,
               aDirty, aDest, aFill, aAnchor, aRepeatSize,
               CSSIntRect(0, 0,
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
-                         nsPresContext::AppUnitsToIntCSSPixels(mSize.height)));
+                         nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
+              aOpacity);
 }
 
 /**
  * Compute the size and position of the master copy of the image. I.e., a single
  * tile used to fill the dest rect.
  * aFill The destination rect to be filled
  * aHFill and aVFill are the repeat patterns for the component -
  * NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
@@ -5995,17 +6003,17 @@ nsImageRenderer::DrawBorderImageComponen
     nsRect tile = ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize);
     CSSIntSize imageSize(srcRect.width, srcRect.height);
     return nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(),
                                               aPresContext,
                                               subImage, imageSize, samplingFilter,
                                               tile, fillRect, repeatSize,
                                               tile.TopLeft(), aDirtyRect,
                                               drawFlags,
-                                              ExtendMode::CLAMP);
+                                              ExtendMode::CLAMP, 1.0);
   }
 
   nsSize repeatSize(aFill.Size());
   nsRect fillRect(aFill);
   nsRect destTile = RequiresScaling(fillRect, aHFill, aVFill, aUnitSize)
                   ? ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize)
                   : fillRect;
   return Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -214,17 +214,18 @@ public:
    * @see nsLayoutUtils::DrawImage() for parameters.
    */
   DrawResult DrawLayer(nsPresContext*       aPresContext,
                        nsRenderingContext&  aRenderingContext,
                        const nsRect&        aDest,
                        const nsRect&        aFill,
                        const nsPoint&       aAnchor,
                        const nsRect&        aDirty,
-                       const nsSize&        aRepeatSize);
+                       const nsSize&        aRepeatSize,
+                       float                aOpacity);
 
   /**
    * Draw the image to a single component of a border-image style rendering.
    * aFill The destination rect to be drawn into
    * aSrc is the part of the image to be rendered into a tile (aUnitSize in
    * aFill), if aSrc and the dest tile are different sizes, the image will be
    * scaled to map aSrc onto the dest tile.
    * aHFill and aVFill are the repeat patterns for the component -
@@ -276,17 +277,18 @@ private:
    */
   DrawResult Draw(nsPresContext*       aPresContext,
                   nsRenderingContext&  aRenderingContext,
                   const nsRect&        aDirtyRect,
                   const nsRect&        aDest,
                   const nsRect&        aFill,
                   const nsPoint&       aAnchor,
                   const nsSize&        aRepeatSize,
-                  const mozilla::CSSIntRect& aSrc);
+                  const mozilla::CSSIntRect& aSrc,
+                  float                aOpacity = 1.0);
 
   /**
    * Helper method for creating a gfxDrawable from mPaintServerFrame or
    * mImageElementSurface.
    * Requires mType is eStyleImageType_Element.
    * Returns null if we cannot create the drawable.
    */
   already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
@@ -629,49 +631,54 @@ struct nsCSSRendering {
     nsRect borderArea;
     nsIFrame* frame;
     uint32_t paintFlags;
     nsRect* bgClipRect = nullptr;
     int32_t layer;                  // -1 means painting all layers; other
                                     // value means painting one specific
                                     // layer only.
     CompositionOp compositionOp;
+    float opacity;
 
     static PaintBGParams ForAllLayers(nsPresContext& aPresCtx,
                                       nsRenderingContext& aRenderingCtx,
                                       const nsRect& aDirtyRect,
                                       const nsRect& aBorderArea,
                                       nsIFrame *aFrame,
-                                      uint32_t aPaintFlags);
+                                      uint32_t aPaintFlags,
+                                      float aOpacity = 1.0);
     static PaintBGParams ForSingleLayer(nsPresContext& aPresCtx,
                                         nsRenderingContext& aRenderingCtx,
                                         const nsRect& aDirtyRect,
                                         const nsRect& aBorderArea,
                                         nsIFrame *aFrame,
                                         uint32_t aPaintFlags,
                                         int32_t aLayer,
-                                        CompositionOp aCompositionOp  = CompositionOp::OP_OVER);
+                                        CompositionOp aCompositionOp  = CompositionOp::OP_OVER,
+                                        float aOpacity = 1.0);
 
   private:
     PaintBGParams(nsPresContext& aPresCtx,
                   nsRenderingContext& aRenderingCtx,
                   const nsRect& aDirtyRect,
                   const nsRect& aBorderArea,
                   nsIFrame* aFrame,
                   uint32_t aPaintFlags,
                   int32_t aLayer,
-                  CompositionOp aCompositionOp)
+                  CompositionOp aCompositionOp,
+                  float aOpacity)
      : presCtx(aPresCtx),
        renderingCtx(aRenderingCtx),
        dirtyRect(aDirtyRect),
        borderArea(aBorderArea),
        frame(aFrame),
        paintFlags(aPaintFlags),
        layer(aLayer),
-       compositionOp(aCompositionOp) {}
+       compositionOp(aCompositionOp),
+       opacity(aOpacity) {}
   };
 
   static DrawResult PaintStyleImageLayer(const PaintBGParams& aParams);
 
 
   /**
    * Same as |PaintStyleImageLayer|, except using the provided style structs.
    * This short-circuits the code that ensures that the root element's
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -752,17 +752,17 @@ nsBaseDragService::DrawDragForImage(nsPr
     RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
     if (!ctx)
       return NS_ERROR_FAILURE;
 
     DrawResult res =
       imgContainer->Draw(ctx, destSize, ImageRegion::Create(destSize),
                          imgIContainer::FRAME_CURRENT,
                          SamplingFilter::GOOD, /* no SVGImageContext */ Nothing(),
-                         imgIContainer::FLAG_SYNC_DECODE);
+                         imgIContainer::FLAG_SYNC_DECODE, 1.0);
     if (res == DrawResult::BAD_IMAGE || res == DrawResult::BAD_ARGS) {
       return NS_ERROR_FAILURE;
     }
     *aSurface = dt->Snapshot();
   } else {
     *aSurface = aCanvas->GetSurfaceSnapshot();
   }