mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Cache the current animated geometry root in nsDisplayListBuilder. (bug 1101260 part 1, r=roc)
This commit is contained in:
parent
b408c910db
commit
e49434ce1c
@ -533,6 +533,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
mCurrentTableItem(nullptr),
|
||||
mCurrentFrame(aReferenceFrame),
|
||||
mCurrentReferenceFrame(aReferenceFrame),
|
||||
mCurrentAnimatedGeometryRoot(aReferenceFrame),
|
||||
mWillChangeBudgetCalculated(false),
|
||||
mDirtyRect(-1,-1,-1,-1),
|
||||
mGlassDisplayItem(nullptr),
|
||||
@ -1088,6 +1089,104 @@ nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame *aFrame,
|
||||
return mReferenceFrame;
|
||||
}
|
||||
|
||||
// Sticky frames are active if their nearest scrollable frame is also active.
|
||||
static bool
|
||||
IsStickyFrameActive(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY);
|
||||
|
||||
// Find the nearest scrollframe.
|
||||
nsIFrame* cursor = aFrame;
|
||||
nsIFrame* parent = aParent;
|
||||
while (parent->GetType() != nsGkAtoms::scrollFrame) {
|
||||
cursor = parent;
|
||||
if ((parent = nsLayoutUtils::GetCrossDocParentFrame(cursor)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
||||
return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent)
|
||||
{
|
||||
if (nsLayoutUtils::IsPopup(aFrame))
|
||||
return true;
|
||||
if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame))
|
||||
return true;
|
||||
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 true;
|
||||
}
|
||||
|
||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
|
||||
if (!parent)
|
||||
return true;
|
||||
|
||||
nsIAtom* parentType = parent->GetType();
|
||||
// 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 == nsGkAtoms::sliderFrame && nsLayoutUtils::IsScrollbarThumbLayerized(aFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
|
||||
IsStickyFrameActive(this, aFrame, parent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentType == nsGkAtoms::scrollFrame) {
|
||||
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
||||
if (sf->IsScrollingActive(this) && sf->GetScrolledFrame() == aFrame) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixed-pos frames are parented by the viewport frame, which has no parent.
|
||||
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aParent) {
|
||||
*aParent = parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
const nsIFrame* aStopAtAncestor = nullptr)
|
||||
{
|
||||
nsIFrame* cursor = aFrame;
|
||||
while (cursor != aStopAtAncestor) {
|
||||
nsIFrame* next;
|
||||
if (aBuilder->IsAnimatedGeometryRoot(cursor, &next))
|
||||
return cursor;
|
||||
cursor = next;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor)
|
||||
{
|
||||
if (aFrame == mCurrentFrame) {
|
||||
return mCurrentAnimatedGeometryRoot;
|
||||
}
|
||||
return ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
|
||||
{
|
||||
mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame));
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -209,7 +209,19 @@ public:
|
||||
*/
|
||||
const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame,
|
||||
nsPoint* aOffset = nullptr);
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether a frame acts as an animated geometry root, optionally
|
||||
* returning the next ancestor to check.
|
||||
*/
|
||||
bool IsAnimatedGeometryRoot(nsIFrame* aFrame, 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* FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor = nullptr);
|
||||
|
||||
/**
|
||||
* @return the root of the display list's frame (sub)tree, whose origin
|
||||
* establishes the coordinate system for the display list
|
||||
@ -311,6 +323,10 @@ public:
|
||||
const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
|
||||
const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
|
||||
const nsPoint& GetCurrentFrameOffsetToReferenceFrame() { return mCurrentOffsetToReferenceFrame; }
|
||||
const nsIFrame* GetCurrentAnimatedGeometryRoot() {
|
||||
return mCurrentAnimatedGeometryRoot;
|
||||
}
|
||||
void RecomputeCurrentAnimatedGeometryRoot();
|
||||
|
||||
/**
|
||||
* Returns true if merging and flattening of display lists should be
|
||||
@ -539,6 +555,7 @@ public:
|
||||
: mBuilder(aBuilder),
|
||||
mPrevFrame(aBuilder->mCurrentFrame),
|
||||
mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
|
||||
mPrevAnimatedGeometryRoot(mBuilder->mCurrentAnimatedGeometryRoot),
|
||||
mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
|
||||
mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
|
||||
mPrevDirtyRect(aBuilder->mDirtyRect),
|
||||
@ -555,6 +572,16 @@ public:
|
||||
aBuilder->FindReferenceFrameFor(aForChild,
|
||||
&aBuilder->mCurrentOffsetToReferenceFrame);
|
||||
}
|
||||
if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
|
||||
if (aBuilder->IsAnimatedGeometryRoot(aForChild)) {
|
||||
aBuilder->mCurrentAnimatedGeometryRoot = aForChild;
|
||||
}
|
||||
} else {
|
||||
// Stop at the previous animated geometry root to help cases that
|
||||
// aren't immediate descendents.
|
||||
aBuilder->mCurrentAnimatedGeometryRoot =
|
||||
aBuilder->FindAnimatedGeometryRootFor(aForChild, aBuilder->mCurrentAnimatedGeometryRoot);
|
||||
}
|
||||
aBuilder->mCurrentFrame = aForChild;
|
||||
aBuilder->mDirtyRect = aDirtyRect;
|
||||
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
|
||||
@ -566,6 +593,11 @@ public:
|
||||
mBuilder->mCurrentReferenceFrame = aFrame;
|
||||
mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
|
||||
}
|
||||
// Return the previous frame's animated geometry root, whether or not the
|
||||
// current frame is an immediate descendant.
|
||||
const nsIFrame* GetPrevAnimatedGeometryRoot() const {
|
||||
return mPrevAnimatedGeometryRoot;
|
||||
}
|
||||
~AutoBuildingDisplayList() {
|
||||
mBuilder->mCurrentFrame = mPrevFrame;
|
||||
mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
|
||||
@ -574,11 +606,13 @@ public:
|
||||
mBuilder->mDirtyRect = mPrevDirtyRect;
|
||||
mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
|
||||
mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler;
|
||||
mBuilder->mCurrentAnimatedGeometryRoot = mPrevAnimatedGeometryRoot;
|
||||
}
|
||||
private:
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
const nsIFrame* mPrevFrame;
|
||||
const nsIFrame* mPrevReferenceFrame;
|
||||
nsIFrame* mPrevAnimatedGeometryRoot;
|
||||
nsDisplayLayerEventRegions* mPrevLayerEventRegions;
|
||||
nsPoint mPrevOffset;
|
||||
nsRect mPrevDirtyRect;
|
||||
@ -795,6 +829,8 @@ private:
|
||||
const nsIFrame* mCurrentReferenceFrame;
|
||||
// The offset from mCurrentFrame to mCurrentReferenceFrame.
|
||||
nsPoint mCurrentOffsetToReferenceFrame;
|
||||
// The animated geometry root for mCurrentFrame.
|
||||
nsIFrame* mCurrentAnimatedGeometryRoot;
|
||||
// will-change budget tracker
|
||||
nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
|
||||
mWillChangeBudget;
|
||||
|
@ -1718,8 +1718,8 @@ nsLayoutUtils::SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayeri
|
||||
reinterpret_cast<void*>(intptr_t(aLayerize)));
|
||||
}
|
||||
|
||||
static bool
|
||||
IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
|
||||
bool
|
||||
nsLayoutUtils::IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
|
||||
{
|
||||
return reinterpret_cast<intptr_t>(aThumbFrame->Properties().Get(ScrollbarThumbLayerized()));
|
||||
}
|
||||
@ -1729,55 +1729,7 @@ nsLayoutUtils::GetAnimatedGeometryRootForFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
const nsIFrame* aStopAtAncestor)
|
||||
{
|
||||
nsIFrame* f = aFrame;
|
||||
nsIFrame* stickyFrame = nullptr;
|
||||
while (f != aStopAtAncestor) {
|
||||
if (nsLayoutUtils::IsPopup(f))
|
||||
break;
|
||||
if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f))
|
||||
break;
|
||||
if (!f->GetParent() &&
|
||||
nsLayoutUtils::ViewportHasDisplayPort(f->PresContext())) {
|
||||
// Viewport frames in a display port need to be animated geometry roots
|
||||
// for background-attachment:fixed elements.
|
||||
break;
|
||||
}
|
||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f);
|
||||
if (!parent)
|
||||
break;
|
||||
nsIAtom* parentType = parent->GetType();
|
||||
// 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 == nsGkAtoms::sliderFrame && IsScrollbarThumbLayerized(f)) {
|
||||
break;
|
||||
}
|
||||
// Sticky frames are active if their nearest scrollable frame
|
||||
// is also active, just keep a record of sticky frames that we
|
||||
// encounter for now.
|
||||
if (f->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
|
||||
!stickyFrame) {
|
||||
stickyFrame = f;
|
||||
}
|
||||
if (parentType == nsGkAtoms::scrollFrame) {
|
||||
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
||||
if (sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == f) {
|
||||
// If we found a sticky frame inside this active scroll frame,
|
||||
// then use that. Otherwise use the scroll frame.
|
||||
if (stickyFrame) {
|
||||
return stickyFrame;
|
||||
}
|
||||
return f;
|
||||
} else {
|
||||
stickyFrame = nullptr;
|
||||
}
|
||||
}
|
||||
// Fixed-pos frames are parented by the viewport frame, which has no parent
|
||||
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
|
||||
return f;
|
||||
}
|
||||
f = parent;
|
||||
}
|
||||
return f;
|
||||
return aBuilder->FindAnimatedGeometryRootFor(aFrame, aStopAtAncestor);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
|
@ -512,6 +512,12 @@ public:
|
||||
*/
|
||||
static void SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayerize);
|
||||
|
||||
/**
|
||||
* Returns whether aThumbFrame wants its own layer due to having called
|
||||
* SetScrollbarThumbLayerization.
|
||||
*/
|
||||
static bool IsScrollbarThumbLayerized(nsIFrame* aThumbFrame);
|
||||
|
||||
/**
|
||||
* Finds the nearest ancestor frame to aItem that is considered to have (or
|
||||
* will have) "animated geometry". For example the scrolled frames of
|
||||
|
@ -2879,6 +2879,8 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
nsRect displayPort;
|
||||
bool usingDisplayport = false;
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
bool wasUsingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), nullptr);
|
||||
|
||||
if (!mIsRoot) {
|
||||
// For a non-root scroll frame, override the value of the display port
|
||||
// base rect, and possibly create a display port if there isn't one
|
||||
@ -2903,6 +2905,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
if (usingDisplayport) {
|
||||
dirtyRect = displayPort;
|
||||
|
||||
// The cached animated geometry root for the display builder is out of
|
||||
// date if we just introduced a new animated geometry root.
|
||||
if (!wasUsingDisplayPort) {
|
||||
aBuilder->RecomputeCurrentAnimatedGeometryRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user