Bug 1412112 - Cache the view id on the ASR to speed up the ViewIDForASR operation. r?mstange
This also moves the function from nsLayoutUtils to be a function on the
ASR itself, which seems more appropriate.
MozReview-Commit-ID: 88lUmYi80P0
--- a/gfx/layers/wr/ScrollingLayersHelper.cpp
+++ b/gfx/layers/wr/ScrollingLayersHelper.cpp
@@ -104,17 +104,17 @@ ScrollingLayersHelper::BeginItem(nsDispl
// would only need to push one thing here and we would be done. However, we
// also care about the ScrollingLayersHelper instance that might be created
// for nested display items, in the case where aItem is a wrapper item. The
// nested ScrollingLayersHelper may rely on things like TopmostScrollId and
// TopmostClipId, so now we need to push at most two things onto the stack.
FrameMetrics::ViewID leafmostId = ids.first.valueOr(FrameMetrics::NULL_SCROLL_ID);
FrameMetrics::ViewID scrollId = aItem->GetActiveScrolledRoot()
- ? nsLayoutUtils::ViewIDForASR(aItem->GetActiveScrolledRoot())
+ ? aItem->GetActiveScrolledRoot()->GetViewId()
: FrameMetrics::NULL_SCROLL_ID;
// If the leafmost ASR is not the same as the item's ASR then we are dealing
// with a case where the item's clip chain is scrolled by something other than
// the item's ASR. So for those cases we need to use the ClipAndScroll API.
bool needClipAndScroll = (leafmostId != scrollId);
// The other scenario where we need to push a ClipAndScroll is when we are
// in a nested display item where the enclosing item pushed a ClipAndScroll,
@@ -232,17 +232,17 @@ ScrollingLayersHelper::RecurseAndDefineC
auto it = mCache.find(aChain);
if (it != mCache.end()) {
ids.second = Some(it->second);
}
}
if (ids.second) {
// If we've already got an id for this clip, we can early-exit
if (aAsr) {
- FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(aAsr);
+ FrameMetrics::ViewID scrollId = aAsr->GetViewId();
MOZ_ASSERT(mBuilder->IsScrollLayerDefined(scrollId));
ids.first = Some(scrollId);
}
return ids;
}
// If not, recurse to ensure all the ancestors are defined
auto ancestorIds = DefineClipChain(
@@ -271,17 +271,17 @@ ScrollingLayersHelper::RecurseAndDefineC
} else {
// But if the ASRs are different, this is the outermost clip that's
// still inside aAsr, and we need to make it a child of aAsr rather
// than aChain->mParent.
ancestorIds.second = Nothing();
}
} else {
MOZ_ASSERT(!ancestorIds.second);
- FrameMetrics::ViewID scrollId = aChain->mASR ? nsLayoutUtils::ViewIDForASR(aChain->mASR) : FrameMetrics::NULL_SCROLL_ID;
+ FrameMetrics::ViewID scrollId = aChain->mASR ? aChain->mASR->GetViewId() : FrameMetrics::NULL_SCROLL_ID;
if (mBuilder->TopmostScrollId() == scrollId) {
if (mBuilder->TopmostIsClip()) {
// If aChain->mASR is already the topmost scroll layer on the stack, but
// but there was another clip pushed *on top* of that ASR, then that clip
// shares the ASR, and we need to make our clip a child of that clip, which
// in turn will already be a descendant of the correct ASR.
// This covers the cases where e.g. the Gecko display list has nested items,
// and the clip chain on the nested item implicitly extends from the clip
@@ -339,17 +339,17 @@ ScrollingLayersHelper::RecurseAndDefineA
int32_t aAppUnitsPerDevPixel,
const StackingContextHelper& aSc)
{
MOZ_ASSERT(aAsr);
// This will hold our return value
std::pair<Maybe<FrameMetrics::ViewID>, Maybe<wr::WrClipId>> ids;
- FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(aAsr);
+ FrameMetrics::ViewID scrollId = aAsr->GetViewId();
if (mBuilder->IsScrollLayerDefined(scrollId)) {
// If we've already defined this scroll layer before, we can early-exit
ids.first = Some(scrollId);
if (aChain) {
if (mBuilder->HasExtraClip()) {
ids.second = mBuilder->GetCacheOverride(aChain);
} else {
auto it = mCache.find(aChain);
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -49,17 +49,17 @@ WebRenderLayerScrollData::Initialize(Web
mDescendantCount = aDescendantCount;
MOZ_ASSERT(aItem);
aItem->UpdateScrollData(&aOwner, this);
for (const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
asr && asr != aStopAtAsr;
asr = asr->mParent) {
MOZ_ASSERT(aOwner.GetManager());
- FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(asr);
+ FrameMetrics::ViewID scrollId = asr->GetViewId();
if (Maybe<size_t> index = aOwner.HasMetadataFor(scrollId)) {
mScrollIds.AppendElement(index.ref());
} else {
Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
nullptr, aOwner.GetManager(), aItem->ReferenceFrame(),
ContainerLayerParameters(), nullptr);
MOZ_ASSERT(metadata);
MOZ_ASSERT(metadata->GetMetrics().GetScrollId() == scrollId);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -863,23 +863,16 @@ nsLayoutUtils::FindContentFor(ViewID aId
if (exists) {
return content;
} else {
return nullptr;
}
}
-ViewID
-nsLayoutUtils::ViewIDForASR(const mozilla::ActiveScrolledRoot* aASR)
-{
- nsIContent* content = aASR->mScrollableFrame->GetScrolledFrame()->GetContent();
- return nsLayoutUtils::FindOrCreateIDFor(content);
-}
-
nsIFrame*
GetScrollFrameFromContent(nsIContent* aContent)
{
nsIFrame* frame = aContent->GetPrimaryFrame();
if (aContent->OwnerDoc()->GetRootElement() == aContent) {
nsIPresShell* presShell = frame ? frame->PresShell() : nullptr;
if (!presShell) {
presShell = aContent->OwnerDoc()->GetShell();
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -182,22 +182,16 @@ public:
static ViewID FindOrCreateIDFor(nsIContent* aContent);
/**
* Find content for given ID.
*/
static nsIContent* FindContentFor(ViewID aId);
/**
- * Find the view ID (or generate a new one) for the content element
- * corresponding to the ASR.
- */
- static ViewID ViewIDForASR(const mozilla::ActiveScrolledRoot* aASR);
-
- /**
* Find the scrollable frame for a given ID.
*/
static nsIScrollableFrame* FindScrollableFrameFor(ViewID aId);
/**
* Find the ID for a given scrollable frame.
*/
static ViewID FindIDForScrollableFrame(nsIScrollableFrame* aScrollable);
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -5032,17 +5032,17 @@ FixUpFixedPositionLayer(Layer* aLayer,
aLeafScrollMetadataASR == aContainerScrollMetadataASR
? aContainerCompositorASR
: aLeafScrollMetadataASR;
// The goal of the annotation is to have the layer move with aTargetASR.
if (compositorASR && aTargetASR != compositorASR) {
// Mark this layer as fixed with respect to the child scroll frame of aTargetASR.
aLayer->SetFixedPositionData(
- nsLayoutUtils::ViewIDForASR(FindDirectChildASR(aTargetASR, compositorASR)),
+ FindDirectChildASR(aTargetASR, compositorASR)->GetViewId(),
aLayer->GetFixedPositionAnchor(),
aLayer->GetFixedPositionSides());
} else {
// Remove the fixed annotation from the layer, unless this layers is fixed
// to the document's root scroll frame - in that case, the annotation is
// needed for hit testing, because fixed layers in iframes should scroll
// the iframe, even though their position is not affected by scrolling in
// the iframe. (The APZ hit testing code has a special case for this.)
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4900,17 +4900,17 @@ nsDisplayCompositorHitTestInfo::CreateWe
// XXX: eventually this scrollId computation and the SetHitTestInfo
// call will get moved out into the WR display item iteration code so that
// we don't need to do it as often, and so that we can do it for other
// display item types as well (reducing the need for as many instances of
// this display item).
FrameMetrics::ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
if (const ActiveScrolledRoot* asr = GetActiveScrolledRoot()) {
- scrollId = nsLayoutUtils::ViewIDForASR(asr);
+ scrollId = asr->GetViewId();
}
// Insert a transparent rectangle with the hit-test info
aBuilder.SetHitTestInfo(scrollId, mHitTestInfo);
aBuilder.PushRect(rect, rect, true, wr::ToColorF(gfx::Color()));
aBuilder.ClearHitTestInfo();
return true;
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -257,16 +257,17 @@ struct ActiveScrolledRoot {
if (aIsRetained) {
RefPtr<ActiveScrolledRoot> ref = asr;
f->SetProperty(ActiveScrolledRootCache(), ref.forget().take());
}
}
asr->mParent = aParent;
asr->mScrollableFrame = aScrollableFrame;
+ asr->mViewId = Nothing();
asr->mDepth = aParent ? aParent->mDepth + 1 : 1;
asr->mRetained = aIsRetained;
return asr.forget();
}
static const ActiveScrolledRoot* PickAncestor(const ActiveScrolledRoot* aOne,
const ActiveScrolledRoot* aTwo)
@@ -285,16 +286,28 @@ struct ActiveScrolledRoot {
static bool IsAncestor(const ActiveScrolledRoot* aAncestor,
const ActiveScrolledRoot* aDescendant);
static nsCString ToString(const mozilla::ActiveScrolledRoot* aActiveScrolledRoot);
// Call this when inserting an ancestor.
void IncrementDepth() { mDepth++; }
+ /**
+ * Find the view ID (or generate a new one) for the content element
+ * corresponding to the ASR.
+ */
+ mozilla::layers::FrameMetrics::ViewID GetViewId() const {
+ if (!mViewId.isSome()) {
+ nsIContent* content = mScrollableFrame->GetScrolledFrame()->GetContent();
+ mViewId = Some(nsLayoutUtils::FindOrCreateIDFor(content));
+ }
+ return *mViewId;
+ }
+
RefPtr<const ActiveScrolledRoot> mParent;
nsIScrollableFrame* mScrollableFrame;
NS_INLINE_DECL_REFCOUNTING(ActiveScrolledRoot)
private:
ActiveScrolledRoot()
{
@@ -314,16 +327,21 @@ private:
NS_RELEASE(aASR);
}
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(ActiveScrolledRootCache, ActiveScrolledRoot, DetachASR)
static uint32_t Depth(const ActiveScrolledRoot* aActiveScrolledRoot) {
return aActiveScrolledRoot ? aActiveScrolledRoot->mDepth : 0;
}
+ // This field is lazily populated in GetViewId(). We don't want to do the
+ // work of populating if webrender is disabled, because it is often not
+ // needed.
+ mutable Maybe<mozilla::layers::FrameMetrics::ViewID> mViewId;
+
uint32_t mDepth;
bool mRetained;
};
}
enum class nsDisplayListBuilderMode : uint8_t {
PAINTING,