Bug 1451168 - Ensure the transforms from ancestor stacking contexts are combined properly. r=jrmuizel
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 01 May 2018 16:31:23 -0400
changeset 472785 d9b0f9b3bc39d811c92b623a87605e521a1631ad
parent 472758 9e6ec0a26b9abaa6dc57a8a8c76cc4d16b6e1493
child 472786 4b8c19afd14ec6a7211493c9595cf19850eccaf0
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1451168
milestone61.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 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