Bug 1098266 - Set correct visible rect on nsDisplayOpacity items that are shuffled around during preserve-3d display list wrapping. r=tn, a=sledru
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 24 Nov 2014 14:03:49 +1300
changeset 234121 b791be231ddaa7c00e8804cdbe0b8296d1f51da9
parent 234120 1caa74d0963e89b9a5952fc4fdd46181bc5784d6
child 234122 a97968919c5efcfb896af9c2d1da6ec1841f7c2b
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewerstn, sledru
bugs1098266
milestone35.0
Bug 1098266 - Set correct visible rect on nsDisplayOpacity items that are shuffled around during preserve-3d display list wrapping. r=tn, a=sledru
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsFrame.cpp
layout/reftests/bugs/1098266-1-ref.html
layout/reftests/bugs/1098266-1.html
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3282,16 +3282,23 @@ nsRect nsDisplayWrapList::GetComponentAl
 }
 
 void
 nsDisplayWrapList::SetVisibleRect(const nsRect& aRect)
 {
   mVisibleRect = aRect;
 }
 
+void
+nsDisplayWrapList::SetReferenceFrame(const nsIFrame* aFrame)
+{
+  mReferenceFrame = aFrame;
+  mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
+}
+
 static nsresult
 WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
   if (!aList->GetTop())
     return NS_OK;
   nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
   if (!item)
     return NS_ERROR_OUT_OF_MEMORY;
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2661,16 +2661,18 @@ public:
   void SetOverrideZIndex(int32_t aZIndex)
   {
     mHasZIndexOverride = true;
     mOverrideZIndex = aZIndex;
   }
 
   void SetVisibleRect(const nsRect& aRect);
 
+  void SetReferenceFrame(const nsIFrame* aFrame);
+
   /**
    * This creates a copy of this item, but wrapping aItem instead of
    * our existing list. Only gets called if this item returned nullptr
    * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from
    * GetUnderlyingFrame().
    */
   virtual nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder,
                                            nsDisplayItem* aItem) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1771,16 +1771,17 @@ WrapPreserve3DListInternal(nsIFrame* aFr
     // and then flush this list into aOutput by wrapping the whole lot with a single
     // nsDisplayTransform.
 
     if (childFrame->GetParent() &&
         (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
       switch (item->GetType()) {
         case nsDisplayItem::TYPE_TRANSFORM: {
           if (!aTemp->IsEmpty()) {
+            // Flush current aTemp contents
             aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
                 aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
           }
           // Override item's clipping with our current clip state (if any). Since we're
           // bubbling up a preserve-3d transformed child to a preserve-3d parent,
           // we can be sure the child doesn't have clip state of its own.
           NS_ASSERTION(!item->GetClip().HasClip(), "Unexpected clip on item");
           const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
@@ -1794,30 +1795,34 @@ WrapPreserve3DListInternal(nsIFrame* aFr
           nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
               list->GetChildren(), aOutput, aIndex, aTemp);
           list->~nsDisplayWrapList();
           break;
         }
         case nsDisplayItem::TYPE_OPACITY: {
           if (!aTemp->IsEmpty()) {
+            // Flush current aTemp contents
             aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
                 aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
           }
           nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
           nsDisplayList output;
           // Call GetChildren, not GetSameCoordinateSystemChildren, because
           // the preserve-3d children of 'opacity' are temporarily not in the
           // same coordinate system as the opacity --- until this wrapping is done.
           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
               opacity->GetChildren(), &output, aIndex, aTemp);
           if (!aTemp->IsEmpty()) {
             output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
                 aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
           }
+
+          opacity->SetVisibleRect(output.GetVisibleRect());
+          opacity->SetReferenceFrame(output.GetBottom()->ReferenceFrame());
           opacity->GetChildren()->AppendToTop(&output);
           opacity->UpdateBounds(aBuilder);
           aOutput->AppendToTop(item);
           break;
         }
         default: {
           if (childFrame->StyleDisplay()->BackfaceIsHidden()) {
             if (!aTemp->IsEmpty()) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1098266-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div style="position: absolute; transform-style: preserve-3d; transform: perspective(600px) scale(0.166667); opacity:0.3">
+  <div style="position: absolute; background: yellow; width:900px; height:100px; transform: translate3d(0, 3000px, 0px) rotateZ(90deg) scale(5); transform-style: preserve-3d;">
+  </div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1098266-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div style="position: absolute; transform-style: preserve-3d; transform: perspective(600px) scale(0.166667); ">
+  <div style="position: absolute; background: yellow; width:900px; height:100px; transform: translate3d(0, 3000px, 0px) rotateZ(90deg) scale(5); transform-style: preserve-3d; opacity:0.3">
+  </div>
+</div>
+</body>
+</html>