Bug 1156238. Always stop at the root reference frame when looking for an animated geometry root. r=roc,mattwoodrow

This removes the "aStopAtAncestor" argument to agr computing functions. In most cases an AGR was passed for the stop at ancestor, so we'd stop at it anyway since it was an AGR. Most of the remaining cases the root reference frame was passed. And in a few cases something else was passed, which we probably don't want (returning something that isn't an AGR and isn't the root reference frame as an AGR).

The ShouldFixToViewport case is a little tricky. We want to get the AGR of the nearest viewport frame, but only if we don't have to cross our root reference frame to get it. This happens in practice for example when a select dropdown has background-attachment: fixed inside it.

Except for the ShouldFixToViewport bit, this patch is a subset of part 3 in bug 1205087 (which has more changes, and has been temporarily backed out, the remaining bits can hopefully land soon).

The ShouldFixToViewport part is by Timothy Nikkel <tnikkel@gmail.com>
This commit is contained in:
Matt Woodrow 2015-11-03 02:03:47 -06:00
parent 252be2a835
commit cf0b78ff4c
5 changed files with 42 additions and 65 deletions

View File

@ -2119,8 +2119,7 @@ ContainerState::GetLayerCreationHint(const nsIFrame* aAnimatedGeometryRoot)
nsIFrame* fParent;
for (const nsIFrame* f = aAnimatedGeometryRoot;
f != mContainerAnimatedGeometryRoot;
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(mBuilder,
fParent, mContainerAnimatedGeometryRoot)) {
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(mBuilder, fParent)) {
fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (!fParent) {
break;
@ -2801,7 +2800,7 @@ PaintedLayerDataTree::GetParentAnimatedGeometryRoot(const nsIFrame* aAnimatedGeo
}
nsIFrame* agr = Builder()->FindAnimatedGeometryRootFor(
const_cast<nsIFrame*>(aAnimatedGeometryRoot), Builder()->RootReferenceFrame());
const_cast<nsIFrame*>(aAnimatedGeometryRoot));
MOZ_ASSERT_IF(agr, nsLayoutUtils::IsAncestorFrameCrossDoc(Builder()->RootReferenceFrame(), agr));
if (agr != aAnimatedGeometryRoot) {
return agr;
@ -2812,7 +2811,7 @@ PaintedLayerDataTree::GetParentAnimatedGeometryRoot(const nsIFrame* aAnimatedGeo
if (!parent) {
return nullptr;
}
return Builder()->FindAnimatedGeometryRootFor(parent, Builder()->RootReferenceFrame());
return Builder()->FindAnimatedGeometryRootFor(parent);
}
void
@ -3791,8 +3790,7 @@ GetScrollClipIntersection(nsDisplayListBuilder* aBuilder, const nsIFrame* aAnima
nsIFrame* fParent;
for (const nsIFrame* f = aAnimatedGeometryRoot;
f != aStopAtAnimatedGeometryRoot;
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(aBuilder,
fParent, aStopAtAnimatedGeometryRoot)) {
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(aBuilder, fParent)) {
fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (!fParent) {
// This means aStopAtAnimatedGeometryRoot was not an ancestor
@ -3906,7 +3904,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
// take ShouldFixToViewport() into account, so it will return something different
// for fixed background items.
animatedGeometryRootForScrollMetadata = nsLayoutUtils::GetAnimatedGeometryRootForFrame(
mBuilder, item->Frame(), item->ReferenceFrame());
mBuilder, item->Frame());
} else {
// For inactive layer subtrees, splitting content into PaintedLayers
// based on animated geometry roots is pointless. It's more efficient
@ -4759,8 +4757,7 @@ ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
nsIFrame* fParent;
for (const nsIFrame* f = aEntry->mAnimatedGeometryRootForScrollMetadata;
f != mContainerAnimatedGeometryRoot;
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(this->mBuilder,
fParent, mContainerAnimatedGeometryRoot)) {
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(this->mBuilder, fParent)) {
fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (!fParent) {
// This means mContainerAnimatedGeometryRoot was not an ancestor
@ -4904,8 +4901,7 @@ ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer
if (!e->mOpaqueRegion.IsEmpty()) {
const nsIFrame* animatedGeometryRootToCover = animatedGeometryRootForOpaqueness;
if (e->mOpaqueForAnimatedGeometryRootParent &&
nsLayoutUtils::GetAnimatedGeometryRootForFrame(mBuilder, e->mAnimatedGeometryRoot->GetParent(),
mContainerAnimatedGeometryRoot)
nsLayoutUtils::GetAnimatedGeometryRootForFrame(mBuilder, e->mAnimatedGeometryRoot->GetParent())
== mContainerAnimatedGeometryRoot) {
animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
data = FindOpaqueRegionEntry(opaqueRegions,

View File

@ -1079,23 +1079,20 @@ nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParen
bool
nsDisplayListBuilder::GetCachedAnimatedGeometryRoot(const nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor,
nsIFrame** aOutResult)
{
AnimatedGeometryRootLookup lookup(aFrame, aStopAtAncestor);
return mAnimatedGeometryRootCache.Get(lookup, aOutResult);
return mAnimatedGeometryRootCache.Get(const_cast<nsIFrame*>(aFrame), aOutResult);
}
static nsIFrame*
ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor = nullptr,
bool aUseCache = false)
{
nsIFrame* cursor = aFrame;
while (cursor != aStopAtAncestor) {
while (cursor != aBuilder->RootReferenceFrame()) {
if (aUseCache) {
nsIFrame* result;
if (aBuilder->GetCachedAnimatedGeometryRoot(cursor, aStopAtAncestor, &result)) {
if (aBuilder->GetCachedAnimatedGeometryRoot(cursor, &result)) {
return result;
}
}
@ -1108,15 +1105,14 @@ ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
}
nsIFrame*
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor)
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame)
{
if (aFrame == mCurrentFrame) {
return mCurrentAnimatedGeometryRoot;
}
nsIFrame* result = ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor, true);
AnimatedGeometryRootLookup lookup(aFrame, aStopAtAncestor);
mAnimatedGeometryRootCache.Put(lookup, result);
nsIFrame* result = ComputeAnimatedGeometryRootFor(this, aFrame, true);
mAnimatedGeometryRootCache.Put(aFrame, result);
return result;
}
@ -1130,8 +1126,8 @@ nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
mAnimatedGeometryRootCache.Clear();
mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame));
AnimatedGeometryRootLookup lookup(mCurrentFrame, nullptr);
mAnimatedGeometryRootCache.Put(lookup, mCurrentAnimatedGeometryRoot);
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), mCurrentAnimatedGeometryRoot));
mAnimatedGeometryRootCache.Put(const_cast<nsIFrame*>(mCurrentFrame), mCurrentAnimatedGeometryRoot);
}
void

View File

@ -260,7 +260,7 @@ public:
* 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);
nsIFrame* FindAnimatedGeometryRootFor(nsIFrame* aFrame);
/**
* @return the root of the display list's frame (sub)tree, whose origin
@ -644,11 +644,11 @@ public:
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->FindAnimatedGeometryRootFor(aForChild);
}
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(),
aBuilder->mCurrentAnimatedGeometryRoot));
aBuilder->mCurrentFrame = aForChild;
aBuilder->mDirtyRect = aDirtyRect;
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
@ -976,12 +976,11 @@ public:
bool IsInWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize);
/**
* Look up the cached animated geometry root for aFrame subject to
* aStopAtAncestor. Store the nsIFrame* result into *aOutResult, and return
* true if the cache was hit. Return false if the cache was not hit.
* Look up the cached animated geometry root for aFrame subject Store the
* nsIFrame* result into *aOutResult, and return true if the cache was hit.
* Return false if the cache was not hit.
*/
bool GetCachedAnimatedGeometryRoot(const nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor,
nsIFrame** aOutResult);
void SetCommittedScrollInfoItemList(nsDisplayList* aScrollInfoItemStorage) {
@ -1113,27 +1112,8 @@ private:
// The animated geometry root for mCurrentFrame.
nsIFrame* mCurrentAnimatedGeometryRoot;
struct AnimatedGeometryRootLookup {
const nsIFrame* mFrame;
const nsIFrame* mStopAtFrame;
AnimatedGeometryRootLookup(const nsIFrame* aFrame, const nsIFrame* aStopAtFrame)
: mFrame(aFrame)
, mStopAtFrame(aStopAtFrame)
{
}
PLDHashNumber Hash() const {
return mozilla::HashBytes(this, sizeof(*this));
}
bool operator==(const AnimatedGeometryRootLookup& aOther) const {
return mFrame == aOther.mFrame && mStopAtFrame == aOther.mStopAtFrame;
}
};
// Cache for storing animated geometry roots for arbitrary frames
nsDataHashtable<nsGenericHashKey<AnimatedGeometryRootLookup>, nsIFrame*>
mAnimatedGeometryRootCache;
nsDataHashtable<nsPtrHashKey<nsIFrame>, nsIFrame*> mAnimatedGeometryRootCache;
// will-change budget tracker
nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
mWillChangeBudget;

View File

@ -1391,12 +1391,17 @@ nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
// static
nsIFrame*
nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame, nsIAtom* aFrameType)
nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame,
nsIAtom* aFrameType,
nsIFrame* aStopAt)
{
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
if (frame->GetType() == aFrameType) {
return frame;
}
if (frame == aStopAt) {
break;
}
}
return nullptr;
}
@ -1866,10 +1871,9 @@ nsLayoutUtils::IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
nsIFrame*
nsLayoutUtils::GetAnimatedGeometryRootForFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor)
nsIFrame* aFrame)
{
return aBuilder->FindAnimatedGeometryRootFor(aFrame, aStopAtAncestor);
return aBuilder->FindAnimatedGeometryRootFor(aFrame);
}
nsIFrame*
@ -1883,12 +1887,12 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
// frames in its document. InvalidateFixedBackgroundFramesFromList in
// nsGfxScrollFrame will not repaint this item when scrolling occurs.
nsIFrame* viewportFrame =
nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame);
NS_ASSERTION(viewportFrame, "no viewport???");
return GetAnimatedGeometryRootForFrame(aBuilder, viewportFrame,
aBuilder->FindReferenceFrameFor(viewportFrame));
nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame, aBuilder->RootReferenceFrame());
if (viewportFrame) {
return GetAnimatedGeometryRootForFrame(aBuilder, viewportFrame);
}
}
return GetAnimatedGeometryRootForFrame(aBuilder, f, aItem->ReferenceFrame());
return GetAnimatedGeometryRootForFrame(aBuilder, f);
}
// static

View File

@ -273,10 +273,13 @@ public:
*
* @param aFrame the frame to start at
* @param aFrameType the frame type to look for
* @param aStopAt a frame to stop at after we checked it
* @return a frame of the given type or nullptr if no
* such ancestor exists
*/
static nsIFrame* GetClosestFrameOfType(nsIFrame* aFrame, nsIAtom* aFrameType);
static nsIFrame* GetClosestFrameOfType(nsIFrame* aFrame,
nsIAtom* aFrameType,
nsIFrame* aStopAt = nullptr);
/**
* Given a frame, search up the frame tree until we find an
@ -554,12 +557,10 @@ public:
/**
* Finds the nearest ancestor frame to aFrame that is considered to have (or
* will have) "animated geometry". This could be aFrame. Returns
* aStopAtAncestor if no closer ancestor is found.
* will have) "animated geometry". This could be aFrame.
*/
static nsIFrame* GetAnimatedGeometryRootForFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor);
nsIFrame* aFrame);
/**
* GetScrollableFrameFor returns the scrollable frame for a scrolled frame