Bug 1404181 - Part 1: Make AnimatedGeometryRoot/ActiveScrolledRoot retained and refcounted on the heap. r?mstange
MozReview-Commit-ID: Gcm5pOAdCeI
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -345,16 +345,21 @@ public:
}
private:
nsIFrame* GetFrameForDir() const; // helper for Is{Physical,Bidi}LTR to find
// the frame whose directionality we use
public:
bool IsScrollbarOnRight() const;
bool IsScrollingActive(nsDisplayListBuilder* aBuilder) const;
+ bool MayBeAsynchronouslyScrolled() const {
+ // If this is true, then we'll build an ASR, and that's what we want
+ // to know I think.
+ return mWillBuildScrollableLayer;
+ }
bool IsMaybeScrollingActive() const;
bool IsProcessingAsyncScroll() const {
return mAsyncScroll != nullptr || mAsyncSmoothMSDScroll != nullptr;
}
void ResetScrollPositionForLayerPixelAlignment()
{
mScrollPosForLayerPixelAlignment = GetScrollPosition();
}
@@ -888,16 +893,19 @@ public:
return NS_OK;
}
virtual bool IsScrollingActive(nsDisplayListBuilder* aBuilder) override {
return mHelper.IsScrollingActive(aBuilder);
}
virtual bool IsMaybeScrollingActive() const override {
return mHelper.IsMaybeScrollingActive();
}
+ virtual bool MayBeAsynchronouslyScrolled() override {
+ return mHelper.MayBeAsynchronouslyScrolled();
+ }
virtual bool IsProcessingAsyncScroll() override {
return mHelper.IsProcessingAsyncScroll();
}
virtual void ResetScrollPositionForLayerPixelAlignment() override {
mHelper.ResetScrollPositionForLayerPixelAlignment();
}
virtual bool DidHistoryRestore() const override {
return mHelper.mDidHistoryRestore;
@@ -1325,16 +1333,19 @@ public:
return NS_OK;
}
virtual bool IsScrollingActive(nsDisplayListBuilder* aBuilder) override {
return mHelper.IsScrollingActive(aBuilder);
}
virtual bool IsMaybeScrollingActive() const override {
return mHelper.IsMaybeScrollingActive();
}
+ virtual bool MayBeAsynchronouslyScrolled() override {
+ return mHelper.MayBeAsynchronouslyScrolled();
+ }
virtual bool IsProcessingAsyncScroll() override {
return mHelper.IsProcessingAsyncScroll();
}
virtual void ResetScrollPositionForLayerPixelAlignment() override {
mHelper.ResetScrollPositionForLayerPixelAlignment();
}
virtual bool DidHistoryRestore() const override {
return mHelper.mDidHistoryRestore;
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -310,16 +310,23 @@ public:
NS_IMETHOD PostScrolledAreaEventForCurrentArea() = 0;
/**
* Returns true if this scrollframe is being "actively scrolled".
* This basically means that we should allocate resources in the
* expectation that scrolling is going to happen.
*/
virtual bool IsScrollingActive(nsDisplayListBuilder* aBuilder) = 0;
+
+ /**
+ * Returns true if this scroll frame might be scrolled
+ * asynchronously by the compositor.
+ */
+ virtual bool MayBeAsynchronouslyScrolled() = 0;
+
/**
* Same as the above except doesn't take into account will-change budget,
* which means that it can be called during display list building.
*/
virtual bool IsMaybeScrollingActive() const = 0;
/**
* Returns true if the scrollframe is currently processing an async
* or smooth scroll.
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -119,22 +119,16 @@ SpammyLayoutWarningsEnabled()
Preferences::GetBool("layout.spammy_warnings.enabled", &sValue);
sValueInitialized = true;
}
return sValue;
}
#endif
-void*
-AnimatedGeometryRoot::operator new(size_t aSize, nsDisplayListBuilder* aBuilder)
-{
- return aBuilder->Allocate(aSize, DisplayItemType::TYPE_ZERO);
-}
-
/* static */ bool
ActiveScrolledRoot::IsAncestor(const ActiveScrolledRoot* aAncestor,
const ActiveScrolledRoot* aDescendant)
{
if (!aAncestor) {
// nullptr is the root
return true;
}
@@ -919,33 +913,34 @@ nsDisplayListBuilder::nsDisplayListBuild
: mReferenceFrame(aReferenceFrame),
mIgnoreScrollFrame(nullptr),
mLayerEventRegions(nullptr),
mCurrentTableItem(nullptr),
mCurrentActiveScrolledRoot(nullptr),
mCurrentContainerASR(nullptr),
mCurrentFrame(aReferenceFrame),
mCurrentReferenceFrame(aReferenceFrame),
- mCurrentAGR(&mRootAGR),
- mRootAGR(aReferenceFrame, nullptr),
+ mRootAGR(AnimatedGeometryRoot::CreateAGRForFrame(aReferenceFrame, nullptr, true, false)),
+ mCurrentAGR(mRootAGR),
mUsedAGRBudget(0),
mDirtyRect(-1,-1,-1,-1),
mGlassDisplayItem(nullptr),
mScrollInfoItemsForHoisting(nullptr),
mActiveScrolledRootForRootScrollframe(nullptr),
mMode(aMode),
mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
mCurrentScrollbarFlags(0),
mPerspectiveItemIndex(0),
mSVGEffectsBuildingDepth(0),
mContainsBlendMode(false),
mIsBuildingScrollbar(false),
mCurrentScrollbarWillHaveLayer(false),
mBuildCaret(aBuildCaret),
+ mRetainingDisplayList(false),
mIgnoreSuppression(false),
mIsAtRootOfPseudoStackingContext(false),
mIncludeAllOutOfFlows(false),
mDescendIntoSubdocuments(true),
mSelectedFramesOnly(false),
mAllowMergingAndFlattening(true),
mWillComputePluginGeometry(false),
mInTransform(false),
@@ -978,29 +973,30 @@ nsDisplayListBuilder::nsDisplayListBuild
static_assert(static_cast<uint32_t>(DisplayItemType::TYPE_MAX) < (1 << TYPE_BITS),
"Check TYPE_MAX should not overflow");
}
void
nsDisplayListBuilder::BeginFrame()
{
nsCSSRendering::BeginFrameTreesLocked();
- mCurrentAGR = &mRootAGR;
- mFrameToAnimatedGeometryRootMap.Put(mReferenceFrame, &mRootAGR);
+ mCurrentAGR = mRootAGR;
+ mFrameToAnimatedGeometryRootMap.Put(mReferenceFrame, mRootAGR);
mIsPaintingToWindow = false;
mIgnoreSuppression = false;
mInTransform = false;
mSyncDecodeImages = false;
}
void
nsDisplayListBuilder::EndFrame()
{
mFrameToAnimatedGeometryRootMap.Clear();
+ mActiveScrolledRoots.Clear();
nsCSSRendering::EndFrameTreesLocked();
}
static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
for (nsIFrame* f = aFrame; f;
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
@@ -1015,32 +1011,35 @@ static void MarkFrameForDisplay(nsIFrame
bool nsDisplayListBuilder::NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem)
{
return aItem == mGlassDisplayItem || aItem->ClearsBackground();
}
AnimatedGeometryRoot*
nsDisplayListBuilder::WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot,
+ bool aIsAsync,
AnimatedGeometryRoot* aParent /* = nullptr */)
{
- MOZ_ASSERT(IsAnimatedGeometryRoot(aAnimatedGeometryRoot) == AGR_YES);
-
- AnimatedGeometryRoot* result = nullptr;
+ DebugOnly<bool> dummy;
+ MOZ_ASSERT(IsAnimatedGeometryRoot(aAnimatedGeometryRoot, dummy) == AGR_YES);
+
+ RefPtr<AnimatedGeometryRoot> result;
if (!mFrameToAnimatedGeometryRootMap.Get(aAnimatedGeometryRoot, &result)) {
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), aAnimatedGeometryRoot));
- AnimatedGeometryRoot* parent = aParent;
+ RefPtr<AnimatedGeometryRoot> parent = aParent;
if (!parent) {
nsIFrame* parentFrame = nsLayoutUtils::GetCrossDocParentFrame(aAnimatedGeometryRoot);
if (parentFrame) {
- nsIFrame* parentAGRFrame = FindAnimatedGeometryRootFrameFor(parentFrame);
- parent = WrapAGRForFrame(parentAGRFrame);
+ bool isAsync;
+ nsIFrame* parentAGRFrame = FindAnimatedGeometryRootFrameFor(parentFrame, isAsync);
+ parent = WrapAGRForFrame(parentAGRFrame, isAsync);
}
}
- result = new (this) AnimatedGeometryRoot(aAnimatedGeometryRoot, parent);
+ result = AnimatedGeometryRoot::CreateAGRForFrame(aAnimatedGeometryRoot, parent, aIsAsync, IsRetainingDisplayList());
mFrameToAnimatedGeometryRootMap.Put(aAnimatedGeometryRoot, result);
}
MOZ_ASSERT(!aParent || result->mParentAGR == aParent);
return result;
}
AnimatedGeometryRoot*
nsDisplayListBuilder::AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR)
@@ -1051,28 +1050,29 @@ nsDisplayListBuilder::AnimatedGeometryRo
nsIFrame* scrolledFrame = aASR->mScrollableFrame->GetScrolledFrame();
return FindAnimatedGeometryRootFor(scrolledFrame);
}
AnimatedGeometryRoot*
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame)
{
if (!IsPaintingToWindow()) {
- return &mRootAGR;
+ return mRootAGR;
}
if (aFrame == mCurrentFrame) {
return mCurrentAGR;
}
- AnimatedGeometryRoot* result = nullptr;
+ RefPtr<AnimatedGeometryRoot> result;
if (mFrameToAnimatedGeometryRootMap.Get(aFrame, &result)) {
return result;
}
- nsIFrame* agrFrame = FindAnimatedGeometryRootFrameFor(aFrame);
- result = WrapAGRForFrame(agrFrame);
+ bool isAsync;
+ nsIFrame* agrFrame = FindAnimatedGeometryRootFrameFor(aFrame, isAsync);
+ result = WrapAGRForFrame(agrFrame, isAsync);
mFrameToAnimatedGeometryRootMap.Put(aFrame, result);
return result;
}
AnimatedGeometryRoot*
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsDisplayItem* aItem)
{
if (aItem->ShouldFixToViewport(this)) {
@@ -1157,19 +1157,16 @@ static void UnmarkFrameForDisplay(nsIFra
nsDisplayListBuilder::~nsDisplayListBuilder() {
NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
"All frames should have been unmarked");
NS_ASSERTION(mPresShellStates.Length() == 0,
"All presshells should have been exited");
NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
- for (ActiveScrolledRoot* asr : mActiveScrolledRoots) {
- asr->ActiveScrolledRoot::~ActiveScrolledRoot();
- }
for (nsDisplayItem* i : mTemporaryItems) {
i->Destroy(this);
}
for (DisplayItemClipChain* c : mClipChainsToDestroy) {
c->DisplayItemClipChain::~DisplayItemClipChain();
}
MOZ_COUNT_DTOR(nsDisplayListBuilder);
@@ -1311,16 +1308,18 @@ nsDisplayListBuilder::LeavePresShell(nsI
if (!mPresShellStates.IsEmpty()) {
nsPresContext* pc = CurrentPresContext();
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
if (docShell) {
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
}
mIsInChromePresContext = pc->IsChrome();
+ } else {
+ mCurrentAGR = mRootAGR;
}
}
void
nsDisplayListBuilder::ResetMarkedFramesForDisplayList()
{
// Unmark and pop off the frames marked for display in this pres shell.
uint32_t firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
@@ -1405,19 +1404,17 @@ void
nsDisplayListBuilder::Destroy(DisplayItemType aType, void* aPtr)
{
}
ActiveScrolledRoot*
nsDisplayListBuilder::AllocateActiveScrolledRoot(const ActiveScrolledRoot* aParent,
nsIScrollableFrame* aScrollableFrame)
{
- void* p = Allocate(sizeof(ActiveScrolledRoot), DisplayItemType::TYPE_ZERO);
- ActiveScrolledRoot* asr =
- new (KnownNotNull, p) ActiveScrolledRoot(aParent, aScrollableFrame);
+ RefPtr<ActiveScrolledRoot> asr = ActiveScrolledRoot::CreateASRForFrame(aParent, aScrollableFrame, IsRetainingDisplayList());
mActiveScrolledRoots.AppendElement(asr);
return asr;
}
const DisplayItemClipChain*
nsDisplayListBuilder::AllocateDisplayItemClipChain(const DisplayItemClip& aClip,
const ActiveScrolledRoot* aASR,
const DisplayItemClipChain* aParent)
@@ -1534,140 +1531,159 @@ IsStickyFrameActive(nsDisplayListBuilder
}
nsIScrollableFrame* sf = do_QueryFrame(parent);
return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor;
}
nsDisplayListBuilder::AGRState
nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame,
+ bool& aIsAsync,
nsIFrame** aParent)
{
+ aIsAsync = false;
if (aFrame == mReferenceFrame) {
+ aIsAsync = true;
return AGR_YES;
}
if (!IsPaintingToWindow()) {
if (aParent) {
*aParent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
}
return AGR_NO;
}
+ nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
+ if (!parent) {
+ aIsAsync = true;
+ return AGR_YES;
+ }
+
+ AGRState result = AGR_NO; // Possible to transition from not being an AGR
+ // to being an AGR without a style change.
+
+ LayoutFrameType parentType = parent->Type();
+
+ if (aFrame->IsTransformed()) {
+ aIsAsync = EffectCompositor::HasAnimationsForCompositor(aFrame, eCSSProperty_transform);
+ result = AGR_YES;
+ }
+
+ if (parentType == LayoutFrameType::Scroll ||
+ parentType == LayoutFrameType::ListControl) {
+ nsIScrollableFrame* sf = do_QueryFrame(parent);
+ if (sf->GetScrolledFrame() == aFrame) {
+ if (sf->IsScrollingActive(this)) {
+ aIsAsync = aIsAsync || sf->MayBeAsynchronouslyScrolled();
+ result = AGR_YES;
+ } else {
+ result = AGR_MAYBE;
+ }
+ }
+ }
+
+ // Finished checking all conditions that might set aIsAsync, so we can
+ // early return now.
+ if (result == AGR_YES) {
+ return result;
+ }
+
if (nsLayoutUtils::IsPopup(aFrame))
return AGR_YES;
if (ActiveLayerTracker::IsOffsetStyleAnimated(aFrame)) {
const bool inBudget = AddToAGRBudget(aFrame);
if (inBudget) {
return AGR_YES;
}
}
if (!aFrame->GetParent() &&
nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext())) {
// Viewport frames in a display port need to be animated geometry roots
// for background-attachment:fixed elements.
return AGR_YES;
}
- if (aFrame->IsTransformed()) {
- return AGR_YES;
- }
-
- nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
- if (!parent)
- return AGR_YES;
-
- bool maybe = false; // Possible to transition from not being an AGR
- // to being an AGR without a style change.
-
- LayoutFrameType parentType = parent->Type();
+
+
// Treat the slider thumb as being as an active scrolled root when it wants
// its own layer so that it can move without repainting.
if (parentType == LayoutFrameType::Slider) {
nsIScrollableFrame* sf = static_cast<nsSliderFrame*>(parent)->GetScrollFrame();
// The word "Maybe" in IsMaybeScrollingActive might be confusing but we do
// indeed need to always consider scroll thumbs as AGRs if
// IsMaybeScrollingActive is true because that is the same condition we use
// in ScrollFrameHelper::AppendScrollPartsTo to layerize scroll thumbs.
if (sf && sf->IsMaybeScrollingActive()) {
return AGR_YES;
}
- maybe = true;
+ result = AGR_MAYBE;
}
if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
if (IsStickyFrameActive(this, aFrame, parent)) {
return AGR_YES;
}
- maybe = true;
- }
-
- if (parentType == LayoutFrameType::Scroll ||
- parentType == LayoutFrameType::ListControl) {
- nsIScrollableFrame* sf = do_QueryFrame(parent);
- if (sf->GetScrolledFrame() == aFrame) {
- if (sf->IsScrollingActive(this)) {
- return AGR_YES;
- }
- maybe = true;
- }
- }
+ result = AGR_MAYBE;
+ }
+
// Fixed-pos frames are parented by the viewport frame, which has no parent.
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
return AGR_YES;
}
if ((aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED) &&
aFrame->IsFrameOfType(nsIFrame::eSVG)) {
// For SVG containers, they always have
// NS_FRAME_MAY_BE_TRANSFORMED bit. However, they would be
// affected by the fragement identifiers in the svgView form at
// runtime without a new style context.
// For example, layout/reftests/svg/fragmentIdentifier-01.xhtml
//
// see https://www.w3.org/TR/SVG/linking.html#SVGFragmentIdentifiers
- maybe = true;
+ result = AGR_MAYBE;
}
if (aParent) {
*aParent = parent;
}
- return !maybe ? AGR_NO : AGR_MAYBE;
+ return result;
}
nsIFrame*
-nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame)
+nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame, bool& aIsAsync)
{
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), aFrame));
nsIFrame* cursor = aFrame;
while (cursor != RootReferenceFrame()) {
nsIFrame* next;
- if (IsAnimatedGeometryRoot(cursor, &next) == AGR_YES)
+ if (IsAnimatedGeometryRoot(cursor, aIsAsync, &next) == AGR_YES)
return cursor;
cursor = next;
}
return cursor;
}
void
nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
{
+ bool isAsync;
if (*mCurrentAGR != mCurrentFrame &&
- IsAnimatedGeometryRoot(const_cast<nsIFrame*>(mCurrentFrame)) == AGR_YES) {
+ IsAnimatedGeometryRoot(const_cast<nsIFrame*>(mCurrentFrame), isAsync) == AGR_YES) {
AnimatedGeometryRoot* oldAGR = mCurrentAGR;
- mCurrentAGR = WrapAGRForFrame(const_cast<nsIFrame*>(mCurrentFrame), mCurrentAGR);
+ mCurrentAGR = WrapAGRForFrame(const_cast<nsIFrame*>(mCurrentFrame), isAsync, mCurrentAGR);
// Iterate the AGR cache and look for any objects that reference the old AGR and check
// to see if they need to be updated. AGRs can be in the cache multiple times, so we may
// end up doing the work multiple times for AGRs that don't change.
for (auto iter = mFrameToAnimatedGeometryRootMap.Iter(); !iter.Done(); iter.Next()) {
- AnimatedGeometryRoot* cached = iter.UserData();
+ RefPtr<AnimatedGeometryRoot> cached = iter.UserData();
if (cached->mParentAGR == oldAGR && cached != mCurrentAGR) {
// It's possible that this cached AGR struct that has the old AGR as a parent
// should instead have mCurrentFrame has a parent.
- nsIFrame* parent = FindAnimatedGeometryRootFrameFor(*cached);
+ nsIFrame* parent = FindAnimatedGeometryRootFrameFor(*cached, isAsync);
MOZ_ASSERT(parent == mCurrentFrame || parent == *oldAGR);
if (parent == mCurrentFrame) {
cached->mParentAGR = mCurrentAGR;
}
}
}
}
}
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -8,16 +8,17 @@
/*
* structures that represent things to be painted (ordered in z-order),
* used during painting and hit testing
*/
#ifndef NSDISPLAYLIST_H_
#define NSDISPLAYLIST_H_
+#include "mozilla/Attributes.h"
#include "gfxContext.h"
#include "mozilla/ArenaAllocator.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Array.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EnumSet.h"
#include "mozilla/Maybe.h"
@@ -148,30 +149,77 @@ typedef mozilla::EnumSet<mozilla::gfx::C
* returning aItem->ReferenceFrame() when we can't find another animated geometry root.
*
* The animated geometry root isn't strongly defined for a frame as transforms and
* background-attachment:fixed can cause it to vary between display items for a given
* frame.
*/
struct AnimatedGeometryRoot
{
- AnimatedGeometryRoot(nsIFrame* aFrame, AnimatedGeometryRoot* aParent)
- : mFrame(aFrame)
- , mParentAGR(aParent)
- {}
+ static already_AddRefed<AnimatedGeometryRoot>
+ CreateAGRForFrame(nsIFrame* aFrame, AnimatedGeometryRoot* aParent, bool aIsAsync, bool aIsRetained)
+ {
+ RefPtr<AnimatedGeometryRoot> result;
+ if (aIsRetained) {
+ result = aFrame->GetProperty(AnimatedGeometryRootCache());
+ }
+
+ if (result) {
+ result->mParentAGR = aParent;
+ result->mIsAsync = aIsAsync;
+ } else {
+ result = new AnimatedGeometryRoot(aFrame, aParent, aIsAsync, aIsRetained);
+ }
+ return result.forget();
+ }
operator nsIFrame*() { return mFrame; }
nsIFrame* operator ->() const { return mFrame; }
- void* operator new(size_t aSize,
- nsDisplayListBuilder* aBuilder);
+ AnimatedGeometryRoot* GetAsyncAGR() {
+ AnimatedGeometryRoot* agr = this;
+ while (!agr->mIsAsync && agr->mParentAGR) {
+ agr = agr->mParentAGR;
+ }
+ return agr;
+ }
+
+ NS_INLINE_DECL_REFCOUNTING(AnimatedGeometryRoot)
nsIFrame* mFrame;
- AnimatedGeometryRoot* mParentAGR;
+ RefPtr<AnimatedGeometryRoot> mParentAGR;
+ bool mIsAsync;
+ bool mIsRetained;
+
+protected:
+ static void DetachAGR(AnimatedGeometryRoot* aAGR) {
+ aAGR->mFrame = nullptr;
+ aAGR->mParentAGR = nullptr;
+ }
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(AnimatedGeometryRootCache, AnimatedGeometryRoot, DetachAGR)
+
+ AnimatedGeometryRoot(nsIFrame* aFrame, AnimatedGeometryRoot* aParent, bool aIsAsync, bool aIsRetained)
+ : mFrame(aFrame)
+ , mParentAGR(aParent)
+ , mIsAsync(aIsAsync)
+ , mIsRetained(aIsRetained)
+ {
+ MOZ_ASSERT(mParentAGR || mIsAsync, "The root AGR should always be treated as an async AGR.");
+ if (mIsRetained) {
+ aFrame->SetProperty(AnimatedGeometryRootCache(), this);
+ }
+ }
+
+ ~AnimatedGeometryRoot()
+ {
+ if (mFrame && mIsRetained) {
+ mFrame->DeleteProperty(AnimatedGeometryRootCache());
+ }
+ }
};
namespace mozilla {
/**
* An active scrolled root (ASR) is similar to an animated geometry root (AGR).
* The differences are:
* - ASRs are only created for async-scrollable scroll frames. This is a
@@ -183,22 +231,41 @@ namespace mozilla {
* that induce ASRs. This is done using AutoCurrentActiveScrolledRootSetter.
* The current ASR is returned by nsDisplayListBuilder::CurrentActiveScrolledRoot().
* - There is no way to go from an nsIFrame pointer to the ASR of that frame.
* If you need to look up an ASR after display list construction, you need
* to store it while the AutoCurrentActiveScrolledRootSetter that creates it
* is on the stack.
*/
struct ActiveScrolledRoot {
- ActiveScrolledRoot(const ActiveScrolledRoot* aParent,
- nsIScrollableFrame* aScrollableFrame)
- : mParent(aParent)
- , mScrollableFrame(aScrollableFrame)
- , mDepth(mParent ? mParent->mDepth + 1 : 1)
+ static already_AddRefed<ActiveScrolledRoot>
+ CreateASRForFrame(const ActiveScrolledRoot* aParent,
+ nsIScrollableFrame* aScrollableFrame,
+ bool aIsRetained)
{
+ nsIFrame* f = do_QueryFrame(aScrollableFrame);
+
+ RefPtr<ActiveScrolledRoot> asr;
+ if (aIsRetained) {
+ asr = f->GetProperty(ActiveScrolledRootCache());
+ }
+
+ if (!asr) {
+ asr = new ActiveScrolledRoot();
+
+ if (aIsRetained) {
+ f->SetProperty(ActiveScrolledRootCache(), asr);
+ }
+ }
+ asr->mParent = aParent;
+ asr->mScrollableFrame = aScrollableFrame;
+ asr->mDepth = aParent ? aParent->mDepth + 1 : 1;
+ asr->mRetained = aIsRetained;
+
+ return asr.forget();
}
static const ActiveScrolledRoot* PickAncestor(const ActiveScrolledRoot* aOne,
const ActiveScrolledRoot* aTwo)
{
MOZ_ASSERT(IsAncestor(aOne, aTwo) || IsAncestor(aTwo, aOne));
return Depth(aOne) <= Depth(aTwo) ? aOne : aTwo;
}
@@ -213,25 +280,46 @@ 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++; }
- const ActiveScrolledRoot* mParent;
+ RefPtr<const ActiveScrolledRoot> mParent;
nsIScrollableFrame* mScrollableFrame;
+ NS_INLINE_DECL_REFCOUNTING(ActiveScrolledRoot)
+
private:
+ ActiveScrolledRoot()
+ {
+ }
+
+ ~ActiveScrolledRoot()
+ {
+ if (mScrollableFrame && mRetained) {
+ nsIFrame* f = do_QueryFrame(mScrollableFrame);
+ f->DeleteProperty(ActiveScrolledRootCache());
+ }
+ }
+
+ static void DetachASR(ActiveScrolledRoot* aASR) {
+ aASR->mParent = nullptr;
+ aASR->mScrollableFrame = nullptr;
+ }
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(ActiveScrolledRootCache, ActiveScrolledRoot, DetachASR)
+
static uint32_t Depth(const ActiveScrolledRoot* aActiveScrolledRoot) {
return aActiveScrolledRoot ? aActiveScrolledRoot->mDepth : 0;
}
uint32_t mDepth;
+ bool mRetained;
};
}
enum class nsDisplayListBuilderMode : uint8_t {
PAINTING,
EVENT_DELIVERY,
PLUGIN_GEOMETRY,
@@ -513,16 +601,18 @@ public:
*/
bool GetAccurateVisibleRegions() { return mMode == nsDisplayListBuilderMode::PLUGIN_GEOMETRY; }
/**
* @return Returns true if we should include the caret in any display lists
* that we make.
*/
bool IsBuildingCaret() { return mBuildCaret; }
+ bool IsRetainingDisplayList() const { return mRetainingDisplayList; }
+
/**
* Allows callers to selectively override the regular paint suppression checks,
* so that methods like GetFrameForPoint work when painting is suppressed.
*/
void IgnorePaintSuppression() { mIgnoreSuppression = true; }
/**
* @return Returns if this builder will ignore paint suppression.
*/
@@ -549,17 +639,17 @@ public:
const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
const nsPoint& GetCurrentFrameOffsetToReferenceFrame() { return mCurrentOffsetToReferenceFrame; }
AnimatedGeometryRoot* GetCurrentAnimatedGeometryRoot() {
return mCurrentAGR;
}
AnimatedGeometryRoot* GetRootAnimatedGeometryRoot() {
- return &mRootAGR;
+ return mRootAGR;
}
void RecomputeCurrentAnimatedGeometryRoot();
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool DebugContains(void* aPtr) {
return mPool.DebugContains(aPtr);
}
@@ -860,20 +950,21 @@ public:
aBuilder->mCurrentReferenceFrame = aForChild;
} else if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition();
} else {
aBuilder->mCurrentReferenceFrame =
aBuilder->FindReferenceFrameFor(aForChild,
&aBuilder->mCurrentOffsetToReferenceFrame);
}
- mCurrentAGRState = aBuilder->IsAnimatedGeometryRoot(aForChild);
+ bool isAsync;
+ mCurrentAGRState = aBuilder->IsAnimatedGeometryRoot(aForChild, isAsync);
if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
if (mCurrentAGRState == AGR_YES) {
- aBuilder->mCurrentAGR = aBuilder->WrapAGRForFrame(aForChild, aBuilder->mCurrentAGR);
+ aBuilder->mCurrentAGR = aBuilder->WrapAGRForFrame(aForChild, isAsync, aBuilder->mCurrentAGR);
}
} else if (aForChild != aBuilder->mCurrentFrame) {
aBuilder->mCurrentAGR = aBuilder->FindAnimatedGeometryRootFor(aForChild);
}
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(), *aBuilder->mCurrentAGR));
aBuilder->mCurrentFrame = aForChild;
aBuilder->mDirtyRect = aDirtyRect;
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
@@ -908,17 +999,17 @@ public:
private:
nsDisplayListBuilder* mBuilder;
AGRState mCurrentAGRState;
const nsIFrame* mPrevFrame;
const nsIFrame* mPrevReferenceFrame;
nsDisplayLayerEventRegions* mPrevLayerEventRegions;
nsPoint mPrevOffset;
nsRect mPrevDirtyRect;
- AnimatedGeometryRoot* mPrevAGR;
+ RefPtr<AnimatedGeometryRoot> mPrevAGR;
bool mPrevIsAtRootOfPseudoStackingContext;
bool mPrevAncestorHasApzAwareEventHandler;
bool mPrevBuildingInvisibleItems;
};
/**
* A helper class to temporarily set the value of mInTransform.
*/
@@ -1438,37 +1529,39 @@ public:
private:
void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame);
/**
* Returns whether a frame acts as an animated geometry root, optionally
* returning the next ancestor to check.
*/
AGRState IsAnimatedGeometryRoot(nsIFrame* aFrame,
+ bool& aIsAsync,
nsIFrame** aParent = nullptr);
/**
* Returns the nearest ancestor frame to aFrame that is considered to have
* (or will have) animated geometry. This can return aFrame.
*/
- nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame);
+ nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame, bool& aIsAsync);
friend class nsDisplayCanvasBackgroundImage;
friend class nsDisplayBackgroundImage;
friend class nsDisplayFixedPosition;
AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsDisplayItem* aItem);
friend class nsDisplayItem;
friend class nsDisplayOwnLayer;
AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsIFrame* aFrame);
AnimatedGeometryRoot* WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot,
+ bool aIsAsync,
AnimatedGeometryRoot* aParent = nullptr);
- nsDataHashtable<nsPtrHashKey<nsIFrame>, AnimatedGeometryRoot*> mFrameToAnimatedGeometryRootMap;
+ nsDataHashtable<nsPtrHashKey<nsIFrame>, RefPtr<AnimatedGeometryRoot>> mFrameToAnimatedGeometryRootMap;
/**
* Add the current frame to the AGR budget if possible and remember
* the outcome. Subsequent calls will return the same value as
* returned here.
*/
bool AddToAGRBudget(nsIFrame* aFrame);
@@ -1521,18 +1614,18 @@ private:
// mCurrentFrame is the frame that we're currently calling (or about to call)
// BuildDisplayList on.
const nsIFrame* mCurrentFrame;
// The reference frame for mCurrentFrame.
const nsIFrame* mCurrentReferenceFrame;
// The offset from mCurrentFrame to mCurrentReferenceFrame.
nsPoint mCurrentOffsetToReferenceFrame;
- AnimatedGeometryRoot* mCurrentAGR;
- AnimatedGeometryRoot mRootAGR;
+ RefPtr<AnimatedGeometryRoot> mRootAGR;
+ RefPtr<AnimatedGeometryRoot> mCurrentAGR;
// will-change budget tracker
nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
mWillChangeBudget;
// Any frame listed in this set is already counted in the budget
// and thus is in-budget.
nsTHashtable<nsPtrHashKey<nsIFrame> > mWillChangeBudgetSet;
@@ -1551,31 +1644,32 @@ private:
// The display item for the Windows window glass background, if any
nsDisplayItem* mGlassDisplayItem;
// A temporary list that we append scroll info items to while building
// display items for the contents of frames with SVG effects.
// Only non-null when ShouldBuildScrollInfoItemsForHoisting() is true.
// This is a pointer and not a real nsDisplayList value because the
// nsDisplayList class is defined below this class, so we can't use it here.
nsDisplayList* mScrollInfoItemsForHoisting;
- nsTArray<ActiveScrolledRoot*> mActiveScrolledRoots;
+ nsTArray<RefPtr<ActiveScrolledRoot>> mActiveScrolledRoots;
AutoTArray<DisplayItemClipChain*, 128> mClipChainsToDestroy;
nsTArray<nsDisplayItem*> mTemporaryItems;
const ActiveScrolledRoot* mActiveScrolledRootForRootScrollframe;
nsDisplayListBuilderMode mMode;
ViewID mCurrentScrollParentId;
ViewID mCurrentScrollbarTarget;
uint32_t mCurrentScrollbarFlags;
Preserves3DContext mPreserves3DCtx;
uint32_t mPerspectiveItemIndex;
int32_t mSVGEffectsBuildingDepth;
bool mContainsBlendMode;
bool mIsBuildingScrollbar;
bool mCurrentScrollbarWillHaveLayer;
bool mBuildCaret;
+ bool mRetainingDisplayList;
bool mIgnoreSuppression;
bool mIsAtRootOfPseudoStackingContext;
bool mIncludeAllOutOfFlows;
bool mDescendIntoSubdocuments;
bool mSelectedFramesOnly;
bool mAllowMergingAndFlattening;
bool mWillComputePluginGeometry;
// True when we're building a display list that's directly or indirectly
@@ -2335,20 +2429,20 @@ protected:
typedef bool (*PrefFunc)(void);
bool ShouldUseAdvancedLayer(LayerManager* aManager, PrefFunc aFunc) const;
bool CanUseAdvancedLayer(LayerManager* aManager) const;
nsIFrame* mFrame;
const DisplayItemClipChain* mClipChain;
const DisplayItemClip* mClip;
- const ActiveScrolledRoot* mActiveScrolledRoot;
+ RefPtr<const ActiveScrolledRoot> mActiveScrolledRoot;
// Result of FindReferenceFrameFor(mFrame), if mFrame is non-null
const nsIFrame* mReferenceFrame;
- struct AnimatedGeometryRoot* mAnimatedGeometryRoot;
+ RefPtr<struct AnimatedGeometryRoot> mAnimatedGeometryRoot;
// Result of ToReferenceFrame(mFrame), if mFrame is non-null
nsPoint mToReferenceFrame;
// This is the rectangle that needs to be painted.
// Display item construction sets this to the dirty rect.
// nsDisplayList::ComputeVisibility sets this to the visible region
// of the item by intersecting the current visible region with the bounds
// of the item. Paint implementations can use this to limit their drawing.
// Guaranteed to be contained in GetBounds().
@@ -4661,17 +4755,17 @@ public:
mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
protected:
// For background-attachment:fixed
nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, uint32_t aIndex);
void Init(nsDisplayListBuilder* aBuilder);
- AnimatedGeometryRoot* mAnimatedGeometryRootForScrollMetadata;
+ RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
uint32_t mIndex;
bool mIsFixedBackground;
};
class nsDisplayTableFixedPosition : public nsDisplayFixedPosition
{
public:
static nsDisplayTableFixedPosition* CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
@@ -5378,18 +5472,18 @@ private:
uint32_t aFlags,
const nsRect* aBoundsOverride);
StoreList mStoredList;
mutable Matrix4x4 mTransform;
// Accumulated transform of ancestors on the preserves-3d chain.
Matrix4x4 mTransformPreserves3D;
ComputeTransformFunction mTransformGetter;
- AnimatedGeometryRoot* mAnimatedGeometryRootForChildren;
- AnimatedGeometryRoot* mAnimatedGeometryRootForScrollMetadata;
+ RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForChildren;
+ RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
nsRect mChildrenVisibleRect;
uint32_t mIndex;
mutable nsRect mBounds;
// True for mBounds is valid.
mutable bool mHasBounds;
// Be forced not to extend 3D context. Since we don't create a
// transform item, a container layer, for every frames in a
// preserves3d context, the transform items of a child preserves3d