Bug 1451168 - Ensure the transforms from ancestor stacking contexts are combined properly. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 01 May 2018 16:31:23 -0400
changeset 790271 7ce0b61f30c707c5f64f7b60d0f0fcdb889d5817
parent 790147 d2a4720d1c334b64d88a51678758c27ba8f03c89
child 790272 8219406a84e243ec710841106e27084a2dc32986
push id108472
push userkgupta@mozilla.com
push dateTue, 01 May 2018 20:31:44 +0000
reviewersjrmuizel
bugs1451168
milestone61.0a1
Bug 1451168 - Ensure the transforms from ancestor stacking contexts are combined properly. r?jrmuizel When passing the transforms from nsDisplayTransform items down to the descendant display items, we need to make sure they are combined properly so that the "ancestor transform" on the APZ side is correctly computed. MozReview-Commit-ID: Di1FBLYGef5
gfx/layers/wr/WebRenderScrollData.cpp
gfx/layers/wr/WebRenderScrollData.h
gfx/layers/wr/WebRenderScrollDataWrapper.h
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -37,45 +37,58 @@ WebRenderLayerScrollData::InitializeRoot
   mDescendantCount = aDescendantCount;
 }
 
 void
 WebRenderLayerScrollData::Initialize(WebRenderScrollData& aOwner,
                                      nsDisplayItem* aItem,
                                      int32_t aDescendantCount,
                                      const ActiveScrolledRoot* aStopAtAsr,
-                                     const Maybe<gfx::Matrix4x4>& aTransform)
+                                     const Maybe<gfx::Matrix4x4>& aAncestorTransform)
 {
   MOZ_ASSERT(aDescendantCount >= 0); // Ensure value is valid
   MOZ_ASSERT(mDescendantCount == -1); // Don't allow re-setting an already set value
   mDescendantCount = aDescendantCount;
 
   MOZ_ASSERT(aItem);
   aItem->UpdateScrollData(&aOwner, this);
-  if (aTransform) {
-    // mTransform might have been set by the UpdateScrollData call above, so
-    // we should combine rather than clobber
-    mTransform = *aTransform * mTransform;
-  }
   for (const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
        asr && asr != aStopAtAsr;
        asr = asr->mParent) {
     MOZ_ASSERT(aOwner.GetManager());
     FrameMetrics::ViewID scrollId = asr->GetViewId();
     if (Maybe<size_t> index = aOwner.HasMetadataFor(scrollId)) {
       mScrollIds.AppendElement(index.ref());
     } else {
       Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
           aOwner.GetManager(), aItem->ReferenceFrame(),
           ContainerLayerParameters(), nullptr);
       MOZ_ASSERT(metadata);
       MOZ_ASSERT(metadata->GetMetrics().GetScrollId() == scrollId);
       mScrollIds.AppendElement(aOwner.AddMetadata(metadata.ref()));
     }
   }
+
+  // aAncestorTransform, if present, is the transform from an ancestor
+  // nsDisplayTransform that was stored on the stacking context in order to
+  // propagate it downwards in the tree. (i.e. |aItem| is a strict descendant of
+  // the nsDisplayTranform which produced aAncestorTransform). We store this
+  // separately from mTransform because in the case where we have multiple
+  // scroll metadata on this layer item, the mAncestorTransform is associated
+  // with the "topmost" scroll metadata, and the mTransform is associated with
+  // the "bottommost" scroll metadata. The code in
+  // WebRenderScrollDataWrapper::GetTransform() is responsible for combining
+  // these transforms and exposing them appropriately. Also, we don't save the
+  // ancestor transform for thumb layers, because those are a special case in
+  // APZ; we need to keep the ancestor transform for the scrollable content that
+  // the thumb scrolls, but not for the thumb itself, as it will result in
+  // incorrect visual positioning of the thumb.
+  if (aAncestorTransform && mScrollbarData.mScrollbarLayerType != ScrollbarLayerType::Thumb) {
+    mAncestorTransform = *aAncestorTransform;
+  }
 }
 
 int32_t
 WebRenderLayerScrollData::GetDescendantCount() const
 {
   MOZ_ASSERT(mDescendantCount >= 0); // check that it was set
   return mDescendantCount;
 }
@@ -109,26 +122,27 @@ WebRenderLayerScrollData::GetTransformTy
 
 void
 WebRenderLayerScrollData::Dump(const WebRenderScrollData& aOwner) const
 {
   printf_stderr("LayerScrollData(%p) descendants %d\n", this, mDescendantCount);
   for (size_t i : mScrollIds) {
     printf_stderr("  metadata: %s\n", Stringify(aOwner.GetScrollMetadata(i)).c_str());
   }
+  printf_stderr("  ancestor transform: %s\n", Stringify(mAncestorTransform).c_str());
   printf_stderr("  transform: %s perspective: %d visible: %s\n",
     Stringify(mTransform).c_str(), mTransformIsPerspective,
     Stringify(mVisibleRegion).c_str());
   printf_stderr("  event regions: %s override: 0x%x\n",
     Stringify(mEventRegions).c_str(), mEventRegionsOverride);
   if (mReferentId) {
     printf_stderr("  ref layers id: 0x%" PRIx64 "\n", uint64_t(*mReferentId));
   }
-  //printf_stderr("  scroll thumb: %s animation: %" PRIu64 "\n",
-  //  Stringify(mScrollThumbData).c_str(), mScrollbarAnimationId);
+  printf_stderr("  scrollbar type: %d animation: %" PRIx64 "\n",
+    (int)mScrollbarData.mScrollbarLayerType, mScrollbarAnimationId);
   printf_stderr("  fixed pos container: %" PRIu64 "\n",
     mFixedPosScrollContainerId);
 }
 
 WebRenderScrollData::WebRenderScrollData()
   : mManager(nullptr)
   , mIsFirstPaint(false)
   , mPaintSequenceNumber(0)
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -43,30 +43,31 @@ public:
   WebRenderLayerScrollData(); // needed for IPC purposes
   ~WebRenderLayerScrollData();
 
   void InitializeRoot(int32_t aDescendantCount);
   void Initialize(WebRenderScrollData& aOwner,
                   nsDisplayItem* aItem,
                   int32_t aDescendantCount,
                   const ActiveScrolledRoot* aStopAtAsr,
-                  const Maybe<gfx::Matrix4x4>& aTransform);
+                  const Maybe<gfx::Matrix4x4>& aAncestorTransform);
 
   int32_t GetDescendantCount() const;
   size_t GetScrollMetadataCount() const;
 
   void AppendScrollMetadata(WebRenderScrollData& aOwner,
                             const ScrollMetadata& aData);
   // Return the ScrollMetadata object that used to be on the original Layer
   // at the given index. Since we deduplicate the ScrollMetadata objects into
   // the array in the owning WebRenderScrollData object, we need to be passed
   // in a reference to that owner as well.
   const ScrollMetadata& GetScrollMetadata(const WebRenderScrollData& aOwner,
                                           size_t aIndex) const;
 
+  gfx::Matrix4x4 GetAncestorTransform() const { return mAncestorTransform; }
   void SetTransform(const gfx::Matrix4x4& aTransform) { mTransform = aTransform; }
   gfx::Matrix4x4 GetTransform() const { return mTransform; }
   CSSTransformMatrix GetTransformTyped() const;
   void SetTransformIsPerspective(bool aTransformIsPerspective) { mTransformIsPerspective = aTransformIsPerspective; }
   bool GetTransformIsPerspective() const { return mTransformIsPerspective; }
 
   void AddEventRegions(const EventRegions& aRegions) { mEventRegions.OrWith(aRegions); }
   EventRegions GetEventRegions() const { return mEventRegions; }
@@ -100,16 +101,17 @@ private:
   // mScrollMetadatas array. This indirection is used to deduplicate the
   // ScrollMetadata objects, since there is usually heavy duplication of them
   // within a layer tree.
   nsTArray<size_t> mScrollIds;
 
   // Various data that we collect from the Layer in Initialize(), serialize
   // over IPC, and use on the parent side in APZ.
 
+  gfx::Matrix4x4 mAncestorTransform;
   gfx::Matrix4x4 mTransform;
   bool mTransformIsPerspective;
   EventRegions mEventRegions;
   LayerIntRegion mVisibleRegion;
   Maybe<LayersId> mReferentId;
   EventRegionsOverride mEventRegionsOverride;
   ScrollbarData mScrollbarData;
   uint64_t mScrollbarAnimationId;
@@ -211,32 +213,34 @@ struct ParamTraits<mozilla::layers::WebR
 {
   typedef mozilla::layers::WebRenderLayerScrollData paramType;
 
   static void
   Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mDescendantCount);
     WriteParam(aMsg, aParam.mScrollIds);
+    WriteParam(aMsg, aParam.mAncestorTransform);
     WriteParam(aMsg, aParam.mTransform);
     WriteParam(aMsg, aParam.mTransformIsPerspective);
     WriteParam(aMsg, aParam.mEventRegions);
     WriteParam(aMsg, aParam.mVisibleRegion);
     WriteParam(aMsg, aParam.mReferentId);
     WriteParam(aMsg, aParam.mEventRegionsOverride);
     WriteParam(aMsg, aParam.mScrollbarData);
     WriteParam(aMsg, aParam.mScrollbarAnimationId);
     WriteParam(aMsg, aParam.mFixedPosScrollContainerId);
   }
 
   static bool
   Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mDescendantCount)
         && ReadParam(aMsg, aIter, &aResult->mScrollIds)
+        && ReadParam(aMsg, aIter, &aResult->mAncestorTransform)
         && ReadParam(aMsg, aIter, &aResult->mTransform)
         && ReadParam(aMsg, aIter, &aResult->mTransformIsPerspective)
         && ReadParam(aMsg, aIter, &aResult->mEventRegions)
         && ReadParam(aMsg, aIter, &aResult->mVisibleRegion)
         && ReadParam(aMsg, aIter, &aResult->mReferentId)
         && ReadParam(aMsg, aIter, &aResult->mEventRegionsOverride)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarData)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarAnimationId)
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h
+++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h
@@ -217,20 +217,30 @@ public:
   {
     return "WebRenderScrollDataWrapper";
   }
 
   gfx::Matrix4x4 GetTransform() const
   {
     MOZ_ASSERT(IsValid());
 
+    // See WebRenderLayerScrollData::Initialize for more context. The ancestor
+    // transform is associated with the "topmost" layer, and the transform is
+    // associated with the "bottommost" layer. If there is only one
+    // scrollmetadata on the layer, then it is both "topmost" and "bottommost"
+    // and we combine the two transforms.
+
+    gfx::Matrix4x4 transform;
+    if (AtTopLayer()) {
+      transform = mLayer->GetAncestorTransform();
+    }
     if (AtBottomLayer()) {
-      return mLayer->GetTransform();
+      transform = transform * mLayer->GetTransform();
     }
-    return gfx::Matrix4x4();
+    return transform;
   }
 
   CSSTransformMatrix GetTransformTyped() const
   {
     return ViewAs<CSSTransformMatrix>(GetTransform());
   }
 
   bool TransformIsPerspective() const