forked from mirrors/gecko-dev
		
	 11b43679d8
			
		
	
	
		11b43679d8
		
	
	
	
	
		
			
			In some cases we get a gecko display list that looks like this: WrapList with asr(<A>, <B>) Item with asr (<B>) and clipchain(<something> [A]) In this case, we would initialize the WebRenderLayerScrollData for the nested item using a stop-at ancestor of A (because that was the leafmost ASR from the containing WrapList) but the item itself has an ASR of B, which is an ancestor of A. So when walking up from B we'd never hit the stop-at ancestor, and so we'd end up duplicating metrics from the containing WRLSD onto the nested WRLSD. This generated an assertion failure in the APZ code. This patch detects this scenario and skips adding metrics on the nested WRLSD. This produces an APZ tree equivalent to what the non-WebRender path would produce. MozReview-Commit-ID: 8eo6pzXXKBd --HG-- extra : rebase_source : 0581c54c4d9fa6ca08249e42b306c7155022bec7
		
			
				
	
	
		
			290 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "mozilla/layers/WebRenderScrollData.h"
 | |
| 
 | |
| #include "Layers.h"
 | |
| #include "LayersLogging.h"
 | |
| #include "mozilla/layers/WebRenderLayerManager.h"
 | |
| #include "mozilla/layout/RenderFrameParent.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "nsDisplayList.h"
 | |
| #include "nsTArray.h"
 | |
| #include "UnitTransforms.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace layers {
 | |
| 
 | |
| WebRenderLayerScrollData::WebRenderLayerScrollData()
 | |
|   : mDescendantCount(-1)
 | |
|   , mTransformIsPerspective(false)
 | |
|   , mEventRegionsOverride(EventRegionsOverride::NoOverride)
 | |
|   , mScrollbarAnimationId(0)
 | |
|   , mFixedPosScrollContainerId(FrameMetrics::NULL_SCROLL_ID)
 | |
| {
 | |
| }
 | |
| 
 | |
| WebRenderLayerScrollData::~WebRenderLayerScrollData()
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderLayerScrollData::InitializeRoot(int32_t aDescendantCount)
 | |
| {
 | |
|   mDescendantCount = aDescendantCount;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderLayerScrollData::Initialize(WebRenderScrollData& aOwner,
 | |
|                                      nsDisplayItem* aItem,
 | |
|                                      int32_t aDescendantCount,
 | |
|                                      const ActiveScrolledRoot* aStopAtAsr,
 | |
|                                      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);
 | |
| 
 | |
|   const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
 | |
|   if (ActiveScrolledRoot::IsAncestor(asr, aStopAtAsr)) {
 | |
|     // If the item's ASR is an ancestor of the stop-at ASR, then we don't need
 | |
|     // any more metrics information because we'll end up duplicating what the
 | |
|     // ancestor WebRenderLayerScrollData already has.
 | |
|     asr = nullptr;
 | |
|   }
 | |
| 
 | |
|   while (asr && asr != aStopAtAsr) {
 | |
|     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()));
 | |
|     }
 | |
|     asr = asr->mParent;
 | |
|   }
 | |
| 
 | |
|   // 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;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| WebRenderLayerScrollData::GetScrollMetadataCount() const
 | |
| {
 | |
|   return mScrollIds.Length();
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderLayerScrollData::AppendScrollMetadata(WebRenderScrollData& aOwner,
 | |
|                                                const ScrollMetadata& aData)
 | |
| {
 | |
|   mScrollIds.AppendElement(aOwner.AddMetadata(aData));
 | |
| }
 | |
| 
 | |
| const ScrollMetadata&
 | |
| WebRenderLayerScrollData::GetScrollMetadata(const WebRenderScrollData& aOwner,
 | |
|                                             size_t aIndex) const
 | |
| {
 | |
|   MOZ_ASSERT(aIndex < mScrollIds.Length());
 | |
|   return aOwner.GetScrollMetadata(mScrollIds[aIndex]);
 | |
| }
 | |
| 
 | |
| CSSTransformMatrix
 | |
| WebRenderLayerScrollData::GetTransformTyped() const
 | |
| {
 | |
|   return ViewAs<CSSTransformMatrix>(GetTransform());
 | |
| }
 | |
| 
 | |
| 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("  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)
 | |
| {
 | |
| }
 | |
| 
 | |
| WebRenderScrollData::WebRenderScrollData(WebRenderLayerManager* aManager)
 | |
|   : mManager(aManager)
 | |
|   , mIsFirstPaint(false)
 | |
|   , mPaintSequenceNumber(0)
 | |
| {
 | |
| }
 | |
| 
 | |
| WebRenderScrollData::~WebRenderScrollData()
 | |
| {
 | |
| }
 | |
| 
 | |
| WebRenderLayerManager*
 | |
| WebRenderScrollData::GetManager() const
 | |
| {
 | |
|   return mManager;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| WebRenderScrollData::AddMetadata(const ScrollMetadata& aMetadata)
 | |
| {
 | |
|   FrameMetrics::ViewID scrollId = aMetadata.GetMetrics().GetScrollId();
 | |
|   auto insertResult = mScrollIdMap.insert(std::make_pair(scrollId, 0));
 | |
|   if (insertResult.second) {
 | |
|     // Insertion took place, therefore it's a scrollId we hadn't seen before
 | |
|     insertResult.first->second = mScrollMetadatas.Length();
 | |
|     mScrollMetadatas.AppendElement(aMetadata);
 | |
|   } // else we didn't insert, because it already existed
 | |
|   return insertResult.first->second;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| WebRenderScrollData::AddLayerData(const WebRenderLayerScrollData& aData)
 | |
| {
 | |
|   mLayerScrollData.AppendElement(aData);
 | |
|   return mLayerScrollData.Length() - 1;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| WebRenderScrollData::GetLayerCount() const
 | |
| {
 | |
|   return mLayerScrollData.Length();
 | |
| }
 | |
| 
 | |
| const WebRenderLayerScrollData*
 | |
| WebRenderScrollData::GetLayerData(size_t aIndex) const
 | |
| {
 | |
|   if (aIndex >= mLayerScrollData.Length()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return &(mLayerScrollData.ElementAt(aIndex));
 | |
| }
 | |
| 
 | |
| const ScrollMetadata&
 | |
| WebRenderScrollData::GetScrollMetadata(size_t aIndex) const
 | |
| {
 | |
|   MOZ_ASSERT(aIndex < mScrollMetadatas.Length());
 | |
|   return mScrollMetadatas[aIndex];
 | |
| }
 | |
| 
 | |
| Maybe<size_t>
 | |
| WebRenderScrollData::HasMetadataFor(const FrameMetrics::ViewID& aScrollId) const
 | |
| {
 | |
|   auto it = mScrollIdMap.find(aScrollId);
 | |
|   return (it == mScrollIdMap.end() ? Nothing() : Some(it->second));
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderScrollData::SetFocusTarget(const FocusTarget& aFocusTarget)
 | |
| {
 | |
|   mFocusTarget = aFocusTarget;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderScrollData::SetIsFirstPaint()
 | |
| {
 | |
|   mIsFirstPaint = true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| WebRenderScrollData::IsFirstPaint() const
 | |
| {
 | |
|   return mIsFirstPaint;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderScrollData::SetPaintSequenceNumber(uint32_t aPaintSequenceNumber)
 | |
| {
 | |
|   mPaintSequenceNumber = aPaintSequenceNumber;
 | |
| }
 | |
| 
 | |
| uint32_t
 | |
| WebRenderScrollData::GetPaintSequenceNumber() const
 | |
| {
 | |
|   return mPaintSequenceNumber;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderScrollData::ApplyUpdates(const ScrollUpdatesMap& aUpdates,
 | |
|                                   uint32_t aPaintSequenceNumber)
 | |
| {
 | |
|   for (const auto& update : aUpdates) {
 | |
|     if (Maybe<size_t> index = HasMetadataFor(update.first)) {
 | |
|       mScrollMetadatas[*index].GetMetrics().UpdatePendingScrollInfo(update.second);
 | |
|     }
 | |
|   }
 | |
|   mPaintSequenceNumber = aPaintSequenceNumber;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebRenderScrollData::Dump() const
 | |
| {
 | |
|   printf_stderr("WebRenderScrollData with %zu layers firstpaint: %d\n",
 | |
|       mLayerScrollData.Length(), mIsFirstPaint);
 | |
|   for (size_t i = 0; i < mLayerScrollData.Length(); i++) {
 | |
|     mLayerScrollData.ElementAt(i).Dump(*this);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool
 | |
| WebRenderScrollData::RepopulateMap()
 | |
| {
 | |
|   MOZ_ASSERT(mScrollIdMap.empty());
 | |
|   for (size_t i = 0; i < mScrollMetadatas.Length(); i++) {
 | |
|     FrameMetrics::ViewID scrollId = mScrollMetadatas[i].GetMetrics().GetScrollId();
 | |
|     mScrollIdMap.emplace(scrollId, i);
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| } // namespace layers
 | |
| } // namespace mozilla
 |