Bug 779029: Try to respect EXTEND_NONE when masking. r=jrmuizel
☠☠ backed out by c2e247f9d207 ☠ ☠
authorBas Schouten <bschouten@mozilla.com>
Fri, 16 Nov 2012 00:30:08 +0000
changeset 113438 224fe2a12a04c5edb6ec7a1b9d0cad1890f8e66f
parent 113437 2c2c6ddb6fe619c0748e425466e23c0f6d510154
child 113439 1a53df18c076a7388496b9d78cceb855ce793735
push id18154
push userbschouten@mozilla.com
push dateFri, 16 Nov 2012 00:32:37 +0000
treeherdermozilla-inbound@224fe2a12a04 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs779029
milestone19.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 779029: Try to respect EXTEND_NONE when masking. r=jrmuizel
gfx/thebes/gfxContext.cpp
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1397,36 +1397,61 @@ gfxContext::GetPattern()
 // masking
 
 void
 gfxContext::Mask(gfxPattern *pattern)
 {
   if (mCairo) {
     cairo_mask(mCairo, pattern->CairoPattern());
   } else {
+    bool needsClip = false;
+    if (pattern->GetType() == gfxPattern::PATTERN_SURFACE &&
+        pattern->Extend() == gfxPattern::EXTEND_NONE) {
+      // In this situation the mask will be fully transparent (i.e. nothing
+      // will be drawn) outside of the bounds of the surface. We can support
+      // that by clipping out drawing to that area.
+      needsClip = true;
+      nsRefPtr<gfxASurface> surf = pattern->GetSurface();
+      gfxPoint offset = surf->GetDeviceOffset();
+
+      Matrix mat = ToMatrix(pattern->GetMatrix());
+      mat.Invert();
+      mat = GetDTTransform() * mat;
+      mDT->SetTransform(mat);
+      mDT->PushClipRect(Rect(offset.x, offset.y, surf->GetSize().width, surf->GetSize().height));
+      mDT->SetTransform(GetDTTransform());
+    }
     mDT->Mask(GeneralPattern(this), *pattern->GetPattern(mDT), DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
+
+    if (needsClip) {
+      mDT->PopClip();
+    }
   }
 }
 
 void
 gfxContext::Mask(gfxASurface *surface, const gfxPoint& offset)
 {
   SAMPLE_LABEL("gfxContext", "Mask");
   if (mCairo) {
     cairo_mask_surface(mCairo, surface->CairoSurface(), offset.x, offset.y);
   } else {
     // Lifetime needs to be limited here as we may simply wrap surface's data.
     RefPtr<SourceSurface> sourceSurf =
       gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
 
     gfxPoint pt = surface->GetDeviceOffset();
+
+    // We clip here to bind to the mask surface bounds, see above.
+    mDT->PushClipRect(Rect(offset.x, offset.y, sourceSurf->GetSize().width, sourceSurf->GetSize().height));
     mDT->Mask(GeneralPattern(this), 
               SurfacePattern(sourceSurf, EXTEND_CLAMP,
                              Matrix(1.0f, 0, 0, 1.0f, Float(offset.x - pt.x), Float(offset.y - pt.y))),
               DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
+    mDT->PopClip();
   }
 }
 
 void
 gfxContext::Paint(gfxFloat alpha)
 {
   SAMPLE_LABEL("gfxContext", "Paint");
   if (mCairo) {