Bug 1223736 - Part 2: Apply mask in correct coordinate space when drawing with 3d transforms with BasicCompositor. r=lsalzman
☠☠ backed out by 57f5e012ebf3 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 18 Mar 2016 18:45:50 +1300
changeset 289411 1982db677df6bbcd00dd4bd06ce906050f2576c6
parent 289410 5813dbb50356f6fe9e7cd59c227d45d37fd87d8e
child 289412 2da6cf4f1870ed7b69896ba8373c97559f2dad2c
push id30102
push userryanvm@gmail.com
push dateSat, 19 Mar 2016 15:23:17 +0000
treeherdermozilla-central@720fb3d55e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1223736
milestone48.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 1223736 - Part 2: Apply mask in correct coordinate space when drawing with 3d transforms with BasicCompositor. r=lsalzman
gfx/layers/basic/BasicCompositor.cpp
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -392,16 +392,35 @@ Transform(DataSourceSurface* aDest,
 
 static inline IntRect
 RoundOut(Rect r)
 {
   r.RoundOut();
   return IntRect(r.x, r.y, r.width, r.height);
 }
 
+static void
+SetupMask(const EffectChain& aEffectChain,
+          DrawTarget* aDest,
+          const IntPoint& aOffset,
+          RefPtr<SourceSurface>& aMaskSurface,
+          Matrix& aMaskTransform)
+{
+  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
+    EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
+    aMaskSurface = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(aDest);
+    if (!aMaskSurface) {
+      gfxWarning() << "Invalid sourceMask effect";
+    }
+    MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
+    aMaskTransform = effectMask->mMaskTransform.As2D();
+    aMaskTransform.PostTranslate(-aOffset.x, -aOffset.y);
+  }
+}
+
 void
 BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                           const gfx::Rect& aClipRect,
                           const EffectChain &aEffectChain,
                           gfx::Float aOpacity,
                           const gfx::Matrix4x4& aTransform,
                           const gfx::Rect& aVisibleRect)
 {
@@ -437,36 +456,29 @@ BasicCompositor::DrawQuad(const gfx::Rec
       return;
     }
 
     // Propagate the coordinate offset to our 2D draw target.
     newTransform = Matrix::Translation(transformBounds.x, transformBounds.y);
 
     // When we apply the 3D transformation, we do it against a temporary
     // surface, so undo the coordinate offset.
-    new3DTransform = Matrix4x4::Translation(aRect.x, aRect.y, 0) * aTransform;
+    new3DTransform = aTransform;
+    new3DTransform.PreTranslate(aRect.x, aRect.y, 0);
   }
 
   buffer->PushClipRect(aClipRect);
 
   newTransform.PostTranslate(-offset.x, -offset.y);
   buffer->SetTransform(newTransform);
 
   RefPtr<SourceSurface> sourceMask;
   Matrix maskTransform;
-  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
-    EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
-    sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest);
-    if (!sourceMask) {
-      gfxWarning() << "Invalid sourceMask effect";
-    }
-    MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
-    MOZ_ASSERT(!effectMask->mIs3D);
-    maskTransform = effectMask->mMaskTransform.As2D();
-    maskTransform.PostTranslate(-offset.x, -offset.y);
+  if (aTransform.Is2D()) {
+    SetupMask(aEffectChain, dest, offset, sourceMask, maskTransform);
   }
 
   CompositionOp blendMode = CompositionOp::OP_OVER;
   if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) {
     blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode;
   }
 
   switch (aEffectChain.mPrimaryEffect->mType) {
@@ -563,18 +575,50 @@ BasicCompositor::DrawQuad(const gfx::Rec
         );
     if (NS_WARN_IF(!temp)) {
       buffer->PopClip();
       return;
     }
 
     Transform(temp, source, new3DTransform, transformBounds.TopLeft());
 
+    SetupMask(aEffectChain, buffer, offset, sourceMask, maskTransform);
+
+    // Adjust for the fact that our content now start at 0,0 instead
+    // of the top left of transformBounds.
     transformBounds.MoveTo(0, 0);
-    buffer->DrawSurface(temp, transformBounds, transformBounds);
+    maskTransform.PostTranslate(-transformBounds.x, -transformBounds.y);
+
+    if (sourceMask) {
+      // Transform the source by it's normal transform, and then the inverse
+      // of the mask transform so that it's in the mask's untransformed
+      // coordinate space.
+      Matrix old = buffer->GetTransform();
+      Matrix sourceTransform = old;
+
+      Matrix inverseMask = maskTransform;
+      inverseMask.Invert();
+
+      sourceTransform *= inverseMask;
+
+      SurfacePattern source(temp, ExtendMode::CLAMP, sourceTransform);
+
+      buffer->PushClipRect(transformBounds);
+
+      // Mask in the untransformed coordinate space, and then transform
+      // by the mask transform to put the result back into destination
+      // coords.
+      buffer->SetTransform(maskTransform);
+      buffer->MaskSurface(source, sourceMask, Point(0, 0));
+      buffer->SetTransform(old);
+
+      buffer->PopClip();
+    } else {
+      buffer->DrawSurface(temp, transformBounds, transformBounds);
+    }
   }
 
   buffer->PopClip();
 }
 
 void
 BasicCompositor::ClearRect(const gfx::Rect& aRect)
 {