Bug 997336 - Account for the DrawTarget 'device offset' when drawing layers with a mask. r=Bas, a=sledru
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 12 May 2014 12:31:27 +1200
changeset 199273 39922bbe9a089dc9c23da1531e2191282fcf6cab
parent 199272 da83ebcf20998efb33f0f6a67050f56ba2f78b37
child 199274 8d43d8f1a99eda652f113f6aa7b043922acecb42
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, sledru
bugs997336
milestone31.0a2
Bug 997336 - Account for the DrawTarget 'device offset' when drawing layers with a mask. r=Bas, a=sledru
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicCanvasLayer.h
gfx/layers/basic/BasicColorLayer.cpp
gfx/layers/basic/BasicImageLayer.cpp
gfx/layers/basic/BasicImplData.h
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayersImpl.cpp
gfx/layers/basic/BasicLayersImpl.h
gfx/layers/basic/BasicThebesLayer.cpp
gfx/thebes/gfxContext.cpp
gfx/thebes/gfxContext.h
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -16,17 +16,19 @@ class gfxContext;
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 void
-BasicCanvasLayer::Paint(DrawTarget* aDT, Layer* aMaskLayer)
+BasicCanvasLayer::Paint(DrawTarget* aDT,
+                        const Point& aDeviceOffset,
+                        Layer* aMaskLayer)
 {
   if (IsHidden())
     return;
 
   FirePreTransactionCallback();
   UpdateTarget();
   FireDidTransactionCallback();
 
@@ -38,17 +40,17 @@ BasicCanvasLayer::Paint(DrawTarget* aDT,
   if (mNeedsYFlip) {
     m = aDT->GetTransform();
     Matrix newTransform = m;
     newTransform.Translate(0.0f, mBounds.height);
     newTransform.Scale(1.0f, -1.0f);
     aDT->SetTransform(newTransform);
   }
 
-  FillRectWithMask(aDT,
+  FillRectWithMask(aDT, aDeviceOffset,
                    Rect(0, 0, mBounds.width, mBounds.height),
                    mSurface, ToFilter(mFilter),
                    DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                    aMaskLayer);
 
   if (mNeedsYFlip) {
     aDT->SetTransform(m);
   }
--- a/gfx/layers/basic/BasicCanvasLayer.h
+++ b/gfx/layers/basic/BasicCanvasLayer.h
@@ -29,17 +29,19 @@ public:
   
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
   
-  virtual void Paint(gfx::DrawTarget* aDT, Layer* aMaskLayer) MOZ_OVERRIDE;
+  virtual void Paint(gfx::DrawTarget* aDT,
+                     const gfx::Point& aDeviceOffset,
+                     Layer* aMaskLayer) MOZ_OVERRIDE;
  
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 
--- a/gfx/layers/basic/BasicColorLayer.cpp
+++ b/gfx/layers/basic/BasicColorLayer.cpp
@@ -39,30 +39,32 @@ public:
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     ColorLayer::SetVisibleRegion(aRegion);
   }
 
-  virtual void Paint(DrawTarget* aDT, Layer* aMaskLayer) MOZ_OVERRIDE
+  virtual void Paint(DrawTarget* aDT,
+                     const gfx::Point& aDeviceOffset,
+                     Layer* aMaskLayer) MOZ_OVERRIDE
   {
     if (IsHidden()) {
       return;
     }
 
     Rect snapped(mBounds.x, mBounds.y, mBounds.width, mBounds.height);
     if (UserToDevicePixelSnapped(snapped, aDT->GetTransform())) {
       Matrix mat = aDT->GetTransform();
       mat.Invert();
       snapped = mat.TransformBounds(snapped);
     }
 
-    FillRectWithMask(aDT, snapped, ToColor(mColor),
+    FillRectWithMask(aDT, aDeviceOffset, snapped, ToColor(mColor),
                      DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                      aMaskLayer);
   }
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
--- a/gfx/layers/basic/BasicImageLayer.cpp
+++ b/gfx/layers/basic/BasicImageLayer.cpp
@@ -39,17 +39,19 @@ public:
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     ImageLayer::SetVisibleRegion(aRegion);
   }
 
-  virtual void Paint(DrawTarget* aDT, Layer* aMaskLayer) MOZ_OVERRIDE;
+  virtual void Paint(DrawTarget* aDT,
+                     const gfx::Point& aDeviceOffset,
+                     Layer* aMaskLayer) MOZ_OVERRIDE;
 
   virtual TemporaryRef<SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
@@ -59,34 +61,37 @@ protected:
   GetAndPaintCurrentImage(DrawTarget* aTarget,
                           float aOpacity,
                           SourceSurface* aMaskSurface);
 
   gfx::IntSize mSize;
 };
 
 void
-BasicImageLayer::Paint(DrawTarget* aDT, Layer* aMaskLayer)
+BasicImageLayer::Paint(DrawTarget* aDT,
+                       const gfx::Point& aDeviceOffset,
+                       Layer* aMaskLayer)
 {
   if (IsHidden() || !mContainer) {
     return;
   }
 
   mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nullptr : BasicManager()->GetImageFactory());
 
   RefPtr<gfx::SourceSurface> surface;
   AutoLockImage autoLock(mContainer, &surface);
   Image *image = autoLock.GetImage();
   gfx::IntSize size = mSize = autoLock.GetSize();
 
   if (!surface || !surface->IsValid()) {
     return;
   }
 
-  FillRectWithMask(aDT, Rect(0, 0, size.width, size.height), surface, ToFilter(mFilter),
+  FillRectWithMask(aDT, aDeviceOffset, Rect(0, 0, size.width, size.height), 
+                   surface, ToFilter(mFilter),
                    DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                    aMaskLayer);
 
   GetContainer()->NotifyPaintedImage(image);
 }
 
 void
 BasicImageLayer::GetAndPaintCurrentImage(DrawTarget* aTarget,
--- a/gfx/layers/basic/BasicImplData.h
+++ b/gfx/layers/basic/BasicImplData.h
@@ -54,17 +54,19 @@ public:
   }
 
   /**
    * Layers that paint themselves, such as ImageLayers, should paint
    * in response to this method call. aContext will already have been
    * set up to account for all the properties of the layer (transform,
    * opacity, etc).
    */
-  virtual void Paint(gfx::DrawTarget* aDT, Layer* aMaskLayer) {}
+  virtual void Paint(gfx::DrawTarget* aDT,
+                     const gfx::Point& aDeviceOffset,
+                     Layer* aMaskLayer) {}
 
   /**
    * Like Paint() but called for ThebesLayers with the additional parameters
    * they need.
    * If mClipToVisibleRegion is set, then the layer must clip to its
    * effective visible region (snapped or unsnapped, it doesn't matter).
    */
   virtual void PaintThebes(gfxContext* aContext,
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -830,16 +830,17 @@ BasicLayerManager::PaintSelfOrChildren(P
   Layer* child = aPaintContext.mLayer->GetFirstChild();
   if (!child) {
     if (aPaintContext.mLayer->AsThebesLayer()) {
       data->PaintThebes(aGroupTarget, aPaintContext.mLayer->GetMaskLayer(),
           aPaintContext.mCallback, aPaintContext.mCallbackData,
           aPaintContext.mReadback);
     } else {
       data->Paint(aGroupTarget->GetDrawTarget(),
+                  aGroupTarget->GetDeviceOffset(),
                   aPaintContext.mLayer->GetMaskLayer());
     }
   } else {
     ReadbackProcessor readback;
     ContainerLayer* container =
         static_cast<ContainerLayer*>(aPaintContext.mLayer);
     if (IsRetained()) {
       readback.BuildUpdates(container);
--- a/gfx/layers/basic/BasicLayersImpl.cpp
+++ b/gfx/layers/basic/BasicLayersImpl.cpp
@@ -14,38 +14,41 @@
 #include "AutoMaskData.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 bool
-GetMaskData(Layer* aMaskLayer, AutoMoz2DMaskData* aMaskData)
+GetMaskData(Layer* aMaskLayer,
+            const Point& aDeviceOffset,
+            AutoMoz2DMaskData* aMaskData)
 {
   if (aMaskLayer) {
     RefPtr<SourceSurface> surface =
       static_cast<BasicImplData*>(aMaskLayer->ImplData())->GetAsSourceSurface();
     if (surface) {
       Matrix transform;
       Matrix4x4 effectiveTransform = aMaskLayer->GetEffectiveTransform();
       DebugOnly<bool> maskIs2D = effectiveTransform.CanDraw2D(&transform);
       NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
+      transform.Translate(-aDeviceOffset.x, -aDeviceOffset.y);
       aMaskData->Construct(transform, surface);
       return true;
     }
   }
   return false;
 }
 
 void
 PaintWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer)
 {
   AutoMoz2DMaskData mask;
-  if (GetMaskData(aMaskLayer, &mask)) {
+  if (GetMaskData(aMaskLayer, Point(), &mask)) {
     if (aOpacity < 1.0) {
       aContext->PushGroup(gfxContentType::COLOR_ALPHA);
       aContext->Paint(aOpacity);
       aContext->PopGroupToSource();
     }
     aContext->SetMatrix(ThebesMatrix(mask.GetTransform()));
     aContext->Mask(mask.GetSurface());
     return;
@@ -73,23 +76,24 @@ FillRectWithMask(DrawTarget* aDT,
     aDT->PopClip();
     return;
   }
 
   aDT->FillRect(aRect, ColorPattern(aColor), aOptions);
 }
 void
 FillRectWithMask(DrawTarget* aDT,
+                 const gfx::Point& aDeviceOffset,
                  const Rect& aRect,
                  const Color& aColor,
                  const DrawOptions& aOptions,
                  Layer* aMaskLayer)
 {
   AutoMoz2DMaskData mask;
-  if (GetMaskData(aMaskLayer, &mask)) {
+  if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) {
     const Matrix& maskTransform = mask.GetTransform();
     FillRectWithMask(aDT, aRect, aColor, aOptions, mask.GetSurface(), &maskTransform);
     return;
   }
 
   FillRectWithMask(aDT, aRect, aColor, aOptions);
 }
 
@@ -128,24 +132,25 @@ FillRectWithMask(DrawTarget* aDT,
   aDT->FillRect(aRect,
                 SurfacePattern(aSurface, aExtendMode,
                                aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
                                aFilter), aOptions);
 }
 
 void
 FillRectWithMask(DrawTarget* aDT,
+                 const gfx::Point& aDeviceOffset,
                  const Rect& aRect,
                  SourceSurface* aSurface,
                  Filter aFilter,
                  const DrawOptions& aOptions,
                  Layer* aMaskLayer)
 {
   AutoMoz2DMaskData mask;
-  if (GetMaskData(aMaskLayer, &mask)) {
+  if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) {
     const Matrix& maskTransform = mask.GetTransform();
     FillRectWithMask(aDT, aRect, aSurface, aFilter, aOptions, ExtendMode::CLAMP,
                      mask.GetSurface(), &maskTransform);
     return;
   }
 
   FillRectWithMask(aDT, aRect, aSurface, aFilter, aOptions, ExtendMode::CLAMP);
 }
--- a/gfx/layers/basic/BasicLayersImpl.h
+++ b/gfx/layers/basic/BasicLayersImpl.h
@@ -77,17 +77,19 @@ protected:
 /*
  * Extract a mask surface for a mask layer
  * Returns true and through outparams a surface for the mask layer if
  * a mask layer is present and has a valid surface and transform;
  * false otherwise.
  * The transform for the layer will be put in aMaskData
  */
 bool
-GetMaskData(Layer* aMaskLayer, AutoMoz2DMaskData* aMaskData);
+GetMaskData(Layer* aMaskLayer,
+            const gfx::Point& aDeviceOffset,
+            AutoMoz2DMaskData* aMaskData);
 
 // Paint the current source to a context using a mask, if present
 void
 PaintWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer);
 
 // Fill the rect with the source, using a mask and opacity, if present
 void
 FillRectWithMask(gfx::DrawTarget* aDT,
@@ -103,23 +105,25 @@ FillRectWithMask(gfx::DrawTarget* aDT,
                  gfx::Filter aFilter,
                  const gfx::DrawOptions& aOptions,
                  gfx::ExtendMode aExtendMode,
                  gfx::SourceSurface* aMaskSource = nullptr,
                  const gfx::Matrix* aMaskTransform = nullptr,
                  const gfx::Matrix* aSurfaceTransform = nullptr);
 void
 FillRectWithMask(gfx::DrawTarget* aDT,
+                 const gfx::Point& aDeviceOffset,
                  const gfx::Rect& aRect,
                  gfx::SourceSurface* aSurface,
                  gfx::Filter aFilter,
                  const gfx::DrawOptions& aOptions,
                  Layer* aMaskLayer);
 void
 FillRectWithMask(gfx::DrawTarget* aDT,
+                 const gfx::Point& aDeviceOffset,
                  const gfx::Rect& aRect,
                  const gfx::Color& aColor,
                  const gfx::DrawOptions& aOptions,
                  Layer* aMaskLayer);
 
 BasicImplData*
 ToData(Layer* aLayer);
 
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -120,17 +120,17 @@ BasicThebesLayer::PaintThebes(gfxContext
   gfxRect clipExtents;
   clipExtents = aContext->GetClipExtents();
 
   // Pull out the mask surface and transform here, because the mask
   // is internal to basic layers
   AutoMoz2DMaskData mask;
   SourceSurface* maskSurface = nullptr;
   Matrix maskTransform;
-  if (GetMaskData(aMaskLayer, &mask)) {
+  if (GetMaskData(aMaskLayer, Point(), &mask)) {
     maskSurface = mask.GetSurface();
     maskTransform = mask.GetTransform();
   }
 
   if (!IsHidden() && !clipExtents.IsEmpty()) {
     mContentClient->DrawTo(this, aContext->GetDrawTarget(), opacity,
                            GetOperator(),
                            maskSurface, &maskTransform);
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -2237,16 +2237,22 @@ gfxContext::GetAzureDeviceSpaceClipBound
         rect.IntersectRect(rect, clip.transform.TransformBounds(clip.rect));
       }
     }
   }
 
   return rect;
 }
 
+Point
+gfxContext::GetDeviceOffset() const
+{
+  return CurrentState().deviceOffset;
+}
+
 Matrix
 gfxContext::GetDeviceTransform() const
 {
   Matrix mat;
   mat.Translate(-CurrentState().deviceOffset.x, -CurrentState().deviceOffset.y);
   return mat;
 }
 
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -652,16 +652,18 @@ public:
 
     /**
      ** Extents - returns user space extent of current path
      **/
     gfxRect GetUserPathExtent();
     gfxRect GetUserFillExtent();
     gfxRect GetUserStrokeExtent();
 
+    mozilla::gfx::Point GetDeviceOffset() const;
+
     /**
      ** Flags
      **/
 
     enum {
         /* If this flag is set, operators other than CLEAR, SOURCE, or
          * OVER will be converted to OVER before being sent to cairo.
          *