Bug 1404181 - Part 14: Add a bunch of new helpers to display list builder and display item for retaining and reusing items. r?mstange
MozReview-Commit-ID: AyiVFa6kofu
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7220,27 +7220,50 @@ nsLayoutUtils::IsPopup(nsIFrame* aFrame)
nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame)
{
// We could use GetRootPresContext() here if the
// NS_FRAME_IN_POPUP frame bit is set.
nsIFrame* f = aFrame;
for (;;) {
if (!f->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
f = f->PresContext()->FrameManager()->GetRootFrame();
+ if (!f) {
+ return aFrame;
+ }
} else if (IsPopup(f)) {
return f;
}
nsIFrame* parent = GetCrossDocParentFrame(f);
if (!parent)
return f;
f = parent;
}
}
/* static */ nsIFrame*
+nsLayoutUtils::GetViewportFrame(nsIFrame* aFrame)
+{
+ nsIFrame* f = aFrame;
+
+ for (;;) {
+ MOZ_ASSERT(f);
+ if (f->Type() == LayoutFrameType::Viewport) {
+ return f;
+ }
+
+ nsIFrame* parent = GetCrossDocParentFrame(f);
+ if (!parent) {
+ return f;
+ }
+
+ f = parent;
+ }
+}
+
+/* static */ nsIFrame*
nsLayoutUtils::GetReferenceFrame(nsIFrame* aFrame)
{
nsIFrame *f = aFrame;
for (;;) {
const nsStyleDisplay* disp = f->StyleDisplay();
if (f->IsTransformed(disp) || f->IsPreserve3DLeaf(disp) || IsPopup(f)) {
return f;
}
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2021,16 +2021,21 @@ public:
/**
* Find the nearest "display root". This is the nearest enclosing
* popup frame or the root prescontext's root frame.
*/
static nsIFrame* GetDisplayRootFrame(nsIFrame* aFrame);
/**
+ * Find the nearest viewport frame that is an ancestor of the given frame.
+ */
+ static nsIFrame* GetViewportFrame(nsIFrame* aFrame);
+
+ /**
* Get the reference frame that would be used when constructing a
* display item for this frame. Rather than using their own frame
* as a reference frame.)
*
* This duplicates some of the logic of GetDisplayRootFrame above and
* of nsDisplayListBuilder::FindReferenceFrameFor.
*
* If you have an nsDisplayListBuilder, you should get the reference
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -904,43 +904,44 @@ nsDisplayListBuilder::AutoCurrentActiveS
}
}
}
mUsed = true;
}
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
- nsDisplayListBuilderMode aMode, bool aBuildCaret)
+ nsDisplayListBuilderMode aMode, bool aBuildCaret, bool aRetainingDisplayList)
: mReferenceFrame(aReferenceFrame),
mIgnoreScrollFrame(nullptr),
mLayerEventRegions(nullptr),
mCurrentTableItem(nullptr),
mCurrentActiveScrolledRoot(nullptr),
mCurrentContainerASR(nullptr),
mCurrentFrame(aReferenceFrame),
mCurrentReferenceFrame(aReferenceFrame),
- mRootAGR(AnimatedGeometryRoot::CreateAGRForFrame(aReferenceFrame, nullptr, true, false)),
+ mRootAGR(AnimatedGeometryRoot::CreateAGRForFrame(aReferenceFrame, nullptr, true, aRetainingDisplayList)),
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),
+ mRetainingDisplayList(aRetainingDisplayList),
+ mPartialUpdate(false),
mIgnoreSuppression(false),
mIsAtRootOfPseudoStackingContext(false),
mIncludeAllOutOfFlows(false),
mDescendIntoSubdocuments(true),
mSelectedFramesOnly(false),
mAllowMergingAndFlattening(true),
mWillComputePluginGeometry(false),
mInTransform(false),
@@ -951,17 +952,18 @@ nsDisplayListBuilder::nsDisplayListBuild
mContainsPluginItem(false),
mAncestorHasApzAwareEventHandler(false),
mHaveScrollableDisplayPort(false),
mWindowDraggingAllowed(false),
mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
mForceLayerForScrollParent(false),
mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)),
mBuildingInvisibleItems(false),
- mHitTestShouldStopAtFirstOpaque(false)
+ mHitTestShouldStopAtFirstOpaque(false),
+ mIsBuilding(false)
{
MOZ_COUNT_CTOR(nsDisplayListBuilder);
nsPresContext* pc = aReferenceFrame->PresContext();
nsIPresShell *shell = pc->PresShell();
if (pc->IsRenderingOnlySelection()) {
nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
if (selcon) {
@@ -2461,33 +2463,30 @@ already_AddRefed<LayerManager> nsDisplay
}
}
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
return layerManager.forget();
}
uint32_t nsDisplayList::Count() const {
- uint32_t count = 0;
- for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
- ++count;
- }
- return count;
+ return mLength;
}
nsDisplayItem* nsDisplayList::RemoveBottom() {
nsDisplayItem* item = mSentinel.mAbove;
if (!item)
return nullptr;
mSentinel.mAbove = item->mAbove;
if (item == mTop) {
// must have been the only item
mTop = &mSentinel;
}
item->mAbove = nullptr;
+ mLength--;
return item;
}
void nsDisplayList::DeleteAll(nsDisplayListBuilder* aBuilder) {
MOZ_DIAGNOSTIC_ASSERT(aBuilder == mBuilder);
nsDisplayItem* item;
while ((item = RemoveBottom()) != nullptr) {
MOZ_DIAGNOSTIC_ASSERT(aBuilder->DebugContains(item));
@@ -2730,16 +2729,17 @@ nsDisplayItem::nsDisplayItem(nsDisplayLi
nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const ActiveScrolledRoot* aActiveScrolledRoot)
: mFrame(aFrame)
, mActiveScrolledRoot(aActiveScrolledRoot)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(aBuilder->IsBuildingInvisibleItems())
, mDisableSubpixelAA(false)
+ , mReusedItem(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
MOZ_COUNT_CTOR(nsDisplayItem);
if (aBuilder->IsRetainingDisplayList()) {
mFrame->AddDisplayItem(this);
}
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -407,17 +407,18 @@ public:
* @param aReferenceFrame the frame at the root of the subtree; its origin
* is the origin of the reference coordinate system for this display list
* @param aMode encodes what the builder is being used for.
* @param aBuildCaret whether or not we should include the caret in any
* display lists that we make.
*/
nsDisplayListBuilder(nsIFrame* aReferenceFrame,
nsDisplayListBuilderMode aMode,
- bool aBuildCaret);
+ bool aBuildCaret,
+ bool aRetainingDisplayList = false);
~nsDisplayListBuilder();
void BeginFrame();
void EndFrame();
void AddTemporaryItem(nsDisplayItem* aItem)
{
mTemporaryItems.AppendElement(aItem);
@@ -601,20 +602,29 @@ public:
* Calling this setter makes us compute accurate visible regions at the cost
* of performance if regions get very complex.
*/
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 IsBuildingCaret() const { return mBuildCaret; }
bool IsRetainingDisplayList() const { return mRetainingDisplayList; }
+ bool IsPartialUpdate() const { return mPartialUpdate; }
+ void SetPartialUpdate(bool aPartial) { mPartialUpdate = aPartial; }
+
+ bool IsBuilding() const { return mIsBuilding; }
+ void SetIsBuilding(bool aIsBuilding)
+ {
+ mIsBuilding = aIsBuilding;
+ }
+
/**
* 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.
*/
@@ -1705,16 +1715,17 @@ private:
Preserves3DContext mPreserves3DCtx;
uint32_t mPerspectiveItemIndex;
int32_t mSVGEffectsBuildingDepth;
bool mContainsBlendMode;
bool mIsBuildingScrollbar;
bool mCurrentScrollbarWillHaveLayer;
bool mBuildCaret;
bool mRetainingDisplayList;
+ bool mPartialUpdate;
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
@@ -1731,16 +1742,17 @@ private:
// which WantsAsyncScroll().
bool mHaveScrollableDisplayPort;
bool mWindowDraggingAllowed;
bool mIsBuildingForPopup;
bool mForceLayerForScrollParent;
bool mAsyncPanZoomEnabled;
bool mBuildingInvisibleItems;
bool mHitTestShouldStopAtFirstOpaque;
+ bool mIsBuilding;
};
class nsDisplayItem;
class nsDisplayList;
/**
* nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
* nsDisplayItemLink holds the link. The lists are linked from lowest to
* highest in z-order.
@@ -1806,16 +1818,17 @@ public:
: mFrame(aFrame)
, mClipChain(nullptr)
, mClip(nullptr)
, mActiveScrolledRoot(nullptr)
, mReferenceFrame(nullptr)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(false)
, mDisableSubpixelAA(false)
+ , mReusedItem(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
MOZ_COUNT_CTOR(nsDisplayItem);
}
protected:
@@ -1875,16 +1888,17 @@ public:
, mClip(aOther.mClip)
, mActiveScrolledRoot(aOther.mActiveScrolledRoot)
, mReferenceFrame(aOther.mReferenceFrame)
, mAnimatedGeometryRoot(aOther.mAnimatedGeometryRoot)
, mToReferenceFrame(aOther.mToReferenceFrame)
, mVisibleRect(aOther.mVisibleRect)
, mForceNotVisible(aOther.mForceNotVisible)
, mDisableSubpixelAA(aOther.mDisableSubpixelAA)
+ , mReusedItem(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
MOZ_COUNT_CTOR(nsDisplayItem);
if (aBuilder->IsRetainingDisplayList()) {
mFrame->AddDisplayItem(this);
}
@@ -1912,16 +1926,18 @@ public:
virtual DisplayItemType GetType() const = 0;
/**
* Pairing this with the GetUnderlyingFrame() pointer gives a key that
* uniquely identifies this display item in the display item tree.
* XXX check nsOptionEventGrabberWrapper/nsXULEventRedirectorWrapper
*/
virtual uint32_t GetPerFrameKey() const { return uint32_t(GetType()); }
+ uint8_t GetFlags() { return GetDisplayItemFlagsForType(GetType()); }
+
/**
* This is called after we've constructed a display list for event handling.
* When this is called, we've already ensured that aRect intersects the
* item's bounds and that clipping has been taking into account.
*
* @param aRect the point or rect being tested, relative to the reference
* frame. If the width and height are both 1 app unit, it indicates we're
* hit testing a point, not a rect.
@@ -1932,17 +1948,24 @@ public:
*/
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {}
/**
* @return the frame that this display item is based on. This is used to sort
* items by z-index and content order and for some other uses. Never
* returns null.
*/
- inline nsIFrame* Frame() const { return mFrame; }
+ inline nsIFrame* Frame() const
+ {
+ MOZ_ASSERT(mFrame, "Trying to use display item after deletion!");
+ return mFrame;
+ }
+
+ bool HasDeletedFrame() const { return !mFrame; }
+
/**
* Compute the used z-index of our frame; returns zero for elements to which
* z-index does not apply, and for z-index:auto.
* @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex.
*/
virtual int32_t ZIndex() const;
/**
* The default bounds is the frame border rect.
@@ -2485,32 +2508,53 @@ public:
* Intersect all clips in our clip chain up to (and including) aASR and set
* set the intersection as this item's clip.
*/
void FuseClipChainUpTo(nsDisplayListBuilder* aBuilder,
const ActiveScrolledRoot* aASR);
bool BackfaceIsHidden() const { return mFrame->BackfaceIsHidden(); }
- bool In3DContextAndBackfaceIsHidden() const
- {
- return Frame()->In3DContextAndBackfaceIsHidden();
+ bool In3DContextAndBackfaceIsHidden()
+ {
+ if (mBackfaceHidden) {
+ return *mBackfaceHidden;
+ }
+
+ // We never need to invalidate this cached value since we're
+ // guaranteed to rebuild the display item entirely if it changes.
+ bool backfaceHidden = Frame()->In3DContextAndBackfaceIsHidden();
+ mBackfaceHidden.emplace(backfaceHidden);
+
+ return backfaceHidden;
}
bool HasSameTypeAndClip(const nsDisplayItem* aOther) const
{
return GetType() == aOther->GetType() &&
GetClipChain() == aOther->GetClipChain();
}
bool HasSameContent(const nsDisplayItem* aOther) const
{
return mFrame->GetContent() == aOther->Frame()->GetContent();
}
+ bool IsReused() const
+ {
+ return mReusedItem;
+ }
+
+ void SetReused(bool aReused)
+ {
+ mReusedItem = aReused;
+ }
+
+ virtual bool CanBeReused() const { return true; }
+
virtual nsIFrame* GetDependentFrame()
{
return nullptr;
}
protected:
nsDisplayItem() = delete;
@@ -2531,20 +2575,22 @@ protected:
// 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().
nsRect mVisibleRect;
bool mForceNotVisible;
bool mDisableSubpixelAA;
+ bool mReusedItem;
#ifdef MOZ_DUMP_PAINTING
// True if this frame has been painted.
bool mPainted;
#endif
+ mozilla::Maybe<bool> mBackfaceHidden;
struct {
nsRect mVisibleRect;
RefPtr<const DisplayItemClipChain> mClipChain;
const DisplayItemClip* mClip;
} mState;
};
@@ -2570,16 +2616,17 @@ public:
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::PaintedLayer PaintedLayer;
/**
* Create an empty list.
*/
explicit nsDisplayList(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder)
+ , mLength(0)
, mIsOpaque(false)
, mForceTransparentSurface(false)
{
mTop = &mSentinel;
mSentinel.mAbove = nullptr;
}
~nsDisplayList() {
if (mSentinel.mAbove) {
@@ -2592,16 +2639,17 @@ public:
* be in a list and cannot be null.
*/
void AppendToTop(nsDisplayItem* aItem) {
NS_ASSERTION(aItem, "No item to append!");
NS_ASSERTION(!aItem->mAbove, "Already in a list!");
MOZ_DIAGNOSTIC_ASSERT(mBuilder->DebugContains(aItem));
mTop->mAbove = aItem;
mTop = aItem;
+ mLength++;
}
/**
* Append a new item to the top of the list. The intended usage is
* AppendNewToTop(new ...);
*/
void AppendNewToTop(nsDisplayItem* aItem) {
if (aItem) {
@@ -2627,28 +2675,31 @@ public:
NS_ASSERTION(aItem, "No item to append!");
NS_ASSERTION(!aItem->mAbove, "Already in a list!");
MOZ_DIAGNOSTIC_ASSERT(mBuilder->DebugContains(aItem));
aItem->mAbove = mSentinel.mAbove;
mSentinel.mAbove = aItem;
if (mTop == &mSentinel) {
mTop = aItem;
}
+ mLength++;
}
/**
* Removes all items from aList and appends them to the top of this list
*/
void AppendToTop(nsDisplayList* aList) {
MOZ_DIAGNOSTIC_ASSERT(mBuilder == aList->mBuilder);
if (aList->mSentinel.mAbove) {
mTop->mAbove = aList->mSentinel.mAbove;
mTop = aList->mTop;
aList->mTop = &aList->mSentinel;
aList->mSentinel.mAbove = nullptr;
+ mLength += aList->mLength;
+ aList->mLength = 0;
}
}
/**
* Removes all items from aList and prepends them to the bottom of this list
*/
void AppendToBottom(nsDisplayList* aList) {
MOZ_DIAGNOSTIC_ASSERT(mBuilder == aList->mBuilder);
@@ -2656,16 +2707,18 @@ public:
aList->mTop->mAbove = mSentinel.mAbove;
mSentinel.mAbove = aList->mSentinel.mAbove;
if (mTop == &mSentinel) {
mTop = aList->mTop;
}
aList->mTop = &aList->mSentinel;
aList->mSentinel.mAbove = nullptr;
+ mLength += aList->mLength;
+ aList->mLength = 0;
}
}
/**
* Remove an item from the bottom of the list and return it.
*/
nsDisplayItem* RemoveBottom();
@@ -2866,23 +2919,21 @@ public:
nsDisplayListBuilder* mBuilder;
void RestoreState() {
mIsOpaque = false;
mForceTransparentSurface = false;
}
private:
- // This class is only used on stack, so we don't have to worry about leaking
- // it. Don't let us be heap-allocated!
- void* operator new(size_t sz) CPP_THROW_NEW;
-
nsDisplayItemLink mSentinel;
nsDisplayItemLink* mTop;
+ uint32_t mLength;
+
// This is set to true by FrameLayerBuilder if the final visible region
// is empty (i.e. everything that was visible is covered by some
// opaque content in this list).
bool mIsOpaque;
// This is set to true by FrameLayerBuilder if any display item in this
// list needs to force the surface containing this list to be transparent.
bool mForceTransparentSurface;
};