Bug 1316719 - Apply scale to the mask layer's contents. r=mattwoodrow
authorMarkus Stange <mstange@themasta.com>
Fri, 11 Nov 2016 13:18:28 -0500
changeset 352322 447eb26dd36a4d64f9236065a8b2859fadfc069b
parent 352321 cee95271302ba9777c77449092e0cba396e6eeb7
child 352323 7cd08d5a029d98157b1548f2b0fc28e62849a2ea
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1316719
milestone52.0a1
Bug 1316719 - Apply scale to the mask layer's contents. r=mattwoodrow MozReview-Commit-ID: 7nd3oL8bFLw
layout/base/FrameLayerBuilder.cpp
layout/reftests/bugs/1316719-1-ref.html
layout/reftests/bugs/1316719-1a.html
layout/reftests/bugs/1316719-1b.html
layout/reftests/bugs/1316719-1c.html
layout/reftests/bugs/reftest.list
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1565,23 +1565,23 @@ struct MaskLayerUserData : public LayerU
  * User data for layers which will be used as masks for css positioned mask.
  */
 struct CSSMaskLayerUserData : public LayerUserData
 {
   CSSMaskLayerUserData()
     : mImageLayers(nsStyleImageLayers::LayerType::Mask)
   { }
 
-  CSSMaskLayerUserData(nsIFrame* aFrame, const nsRect& aBound)
+  CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntRect& aBounds)
     : mImageLayers(aFrame->StyleSVGReset()->mMask),
       mContentRect(aFrame->GetContentRectRelativeToSelf()),
       mPaddingRect(aFrame->GetPaddingRectRelativeToSelf()),
       mBorderRect(aFrame->GetRectRelativeToSelf()),
       mMarginRect(aFrame->GetMarginRectRelativeToSelf()),
-      mBounds(aBound)
+      mBounds(aBounds)
   {
     Hash(aFrame);
   }
 
   CSSMaskLayerUserData& operator=(const CSSMaskLayerUserData& aOther)
   {
     mImageLayers = aOther.mImageLayers;
 
@@ -1645,17 +1645,17 @@ private:
 
   nsStyleImageLayers mImageLayers;
 
   nsRect mContentRect;
   nsRect mPaddingRect;
   nsRect mBorderRect;
   nsRect mMarginRect;
 
-  nsRect mBounds;
+  nsIntRect mBounds;
 
   uint32_t mHash;
 };
 
 /*
  * A helper object to create a draw target for painting mask and create a
  * image container to hold the drawing result. The caller can then bind this
  * image container with a image mask layer via ImageLayer::SetContainer.
@@ -3909,56 +3909,51 @@ ContainerState::SetupMaskLayerForCSSMask
       }
     );
 
   CSSMaskLayerUserData* oldUserData =
     static_cast<CSSMaskLayerUserData*>(maskLayer->GetUserData(&gCSSMaskLayerUserData));
 
   bool snap;
   nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
-  CSSMaskLayerUserData newUserData(aMaskItem->Frame(), bounds);
+  nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
+  CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect);
   if (*oldUserData == newUserData) {
     aLayer->SetMaskLayer(maskLayer);
     return;
   }
 
-  const nsIFrame* frame = aMaskItem->Frame();
-  int32_t A2D = frame->PresContext()->AppUnitsPerDevPixel();
-  Rect devBounds = NSRectToRect(bounds, A2D);
-  uint32_t maxSize = mManager->GetMaxTextureSize();
-  gfx::Size surfaceSize(std::min<gfx::Float>(devBounds.Width(), maxSize),
-                        std::min<gfx::Float>(devBounds.Height(), maxSize));
-  IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width),
-                         NSToIntCeil(surfaceSize.height));
-
-  if (surfaceSizeInt.IsEmpty()) {
+  int32_t maxSize = mManager->GetMaxTextureSize();
+  IntSize surfaceSize(std::min(itemRect.width, maxSize),
+                      std::min(itemRect.height, maxSize));
+
+  if (surfaceSize.IsEmpty()) {
     return;
   }
 
-  MaskImageData imageData(surfaceSizeInt, mManager);
+  MaskImageData imageData(surfaceSize, mManager);
   RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
   if (!dt || !dt->IsValid()) {
     NS_WARNING("Could not create DrawTarget for mask layer.");
     return;
   }
 
   RefPtr<gfxContext> maskCtx = gfxContext::CreateOrNull(dt);
-  gfxPoint offset = nsLayoutUtils::PointToGfxPoint(bounds.TopLeft(), A2D);
-  maskCtx->SetMatrix(gfxMatrix::Translation(-offset));
+  maskCtx->SetMatrix(gfxMatrix::Translation(-itemRect.TopLeft()));
+  maskCtx->Multiply(gfxMatrix::Scaling(mParameters.mXScale, mParameters.mYScale));
 
   if (!aMaskItem->PaintMask(mBuilder, maskCtx)) {
     // Mostly because of mask resource is not ready.
     return;
   }
 
   // Setup mask layer offset.
   Matrix4x4 matrix;
-  matrix.PreTranslate(offset.x, offset.y, 0);
+  matrix.PreTranslate(itemRect.x, itemRect.y, 0);
   matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
-  matrix.PreScale(mParameters.mXScale, mParameters.mYScale, 1.0);
 
   maskLayer->SetBaseTransform(matrix);
 
   RefPtr<ImageContainer> imgContainer =
     imageData.CreateImageAndImageContainer();
   if (!imgContainer) {
     return;
   }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1316719-1-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>reference: 0.8 opacity green circle</title>
+<style>
+
+body {
+  margin: 0;
+}
+
+div {
+  margin: 100px 200px;
+  width: 200px;
+  height: 200px;
+  background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 200"><circle cx="100" cy="100" r="100" fill="green" fill-opacity="0.8"/></svg>');
+}
+
+</style>
+
+<div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1316719-1a.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mask-image with scale transform</title>
+<style>
+
+body {
+  margin: 0;
+}
+
+#transform {
+  width: 10px;
+  height: 10px;
+  transform: scale(20);
+  transform-origin: top left;
+  padding: 5px 10px;
+}
+
+#opacity {
+  opacity: 0.8;
+}
+
+#mask {
+  width: 10px;
+  height: 10px;
+  background: green;
+  mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="black"/></svg>');
+}
+
+#activator {
+  border: 1px solid transparent;
+  will-change: transform;
+}
+
+</style>
+
+<div id="transform">
+  <div id="opacity">
+    <div id="mask">
+      <div id="activator"></div>
+    </div>
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1316719-1b.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mask-image with scale transform</title>
+<style>
+
+body {
+  margin: 0;
+}
+
+#transform {
+  width: 10px;
+  height: 10px;
+  transform: scale(20);
+  transform-origin: top left;
+  padding: 5px 10px;
+}
+
+#opacity {
+  opacity: 0.8;
+}
+
+#mask {
+  width: 10px;
+  height: 10px;
+  background: green;
+  mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="black"/></svg>');
+}
+
+</style>
+
+<div id="transform">
+  <div id="opacity">
+    <div id="mask"></div>
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1316719-1c.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mask-image with scale transform</title>
+<style>
+
+body {
+  margin: 0;
+}
+
+#transform {
+  width: 10px;
+  height: 10px;
+  transform: scale(20);
+  transform-origin: top left;
+  padding: 5px 10px;
+}
+
+#mask {
+  width: 10px;
+  height: 10px;
+  background: green;
+  mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="black" fill-opacity="0.8"/></svg>');
+}
+
+</style>
+
+<div id="transform">
+  <div id="mask"></div>
+</div>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1969,14 +1969,17 @@ random-if(!winWidget) == 1273154-2.html 
 == 1288255.html 1288255-ref.html
 fuzzy(8,1900) == 1291528.html 1291528-ref.html
 # Buttons in 2 pages have different position and the rendering result can be
 # different, but they should use the same button style and the background color
 # should be same.  |fuzzy()| here allows the difference in border, but not
 # background color.
 fuzzy(255,1000) skip-if(!cocoaWidget) == 1294102-1.html 1294102-1-ref.html
 == 1315632-1.html 1315632-1-ref.html
+fuzzy(2,40000) == 1316719-1a.html 1316719-1-ref.html
+fuzzy(2,40000) == 1316719-1b.html 1316719-1-ref.html
+fuzzy(2,40000) == 1316719-1c.html 1316719-1-ref.html
 
 HTTP == 652991-1a.html 652991-1-ref.html
 HTTP == 652991-1b.html 652991-1-ref.html
 HTTP == 652991-2.html 652991-2-ref.html
 HTTP == 652991-3.html 652991-3-ref.html
 HTTP == 652991-4.html 652991-4-ref.html