From d34ff747ee081e5145de42db3e73a146500e62f4 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 18 Feb 2014 14:26:57 +1300 Subject: [PATCH] Bug 972713. Part 1: Make all callers of GetAnimatedGeometryRootFor pass a display item so we can stop searching when we reach the item's reference frame. r=mattwoodrow This guarantees that the animated geometry root for an item is always in the same display list coordinate system as the frame. --HG-- extra : rebase_source : 974434342459b76d62d89fdc04c22c518bf0c58b --- layout/base/nsDisplayList.cpp | 49 ++++++++++++++++------------------- layout/base/nsDisplayList.h | 11 -------- layout/base/nsLayoutUtils.cpp | 21 ++++++++------- layout/base/nsLayoutUtils.h | 24 +++++++---------- 4 files changed, 42 insertions(+), 63 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 5a0859b498da..9dddee0f9074 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3098,18 +3098,23 @@ void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder, NS_ERROR("nsDisplayWrapList should have been flattened away for painting"); } +/** + * Returns true if all descendant display items can be placed in the same + * ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE, + * and they all have the expected animated geometry root. + */ static LayerState -RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder, - LayerManager* aManager, - const ContainerLayerParameters& aParameters, - const nsDisplayList& aList, - nsIFrame* aAnimatedGeometryRoot) +RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters, + const nsDisplayList& aList, + nsIFrame* aExpectedAnimatedGeometryRootForChildren) { LayerState result = LAYER_INACTIVE; for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) { - nsIFrame* f = i->Frame(); if (result == LAYER_INACTIVE && - nsLayoutUtils::GetAnimatedGeometryRootFor(f) != aAnimatedGeometryRoot) { + nsLayoutUtils::GetAnimatedGeometryRootFor(i, aBuilder) != + aExpectedAnimatedGeometryRootForChildren) { result = LAYER_ACTIVE; } @@ -3125,8 +3130,8 @@ RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder, nsDisplayList* list = i->GetSameCoordinateSystemChildren(); if (list) { LayerState childState = - RequiredLayerStateForChildrenInternal(aBuilder, aManager, aParameters, *list, - aAnimatedGeometryRoot); + RequiredLayerStateForChildren(aBuilder, aManager, aParameters, *list, + aExpectedAnimatedGeometryRootForChildren); if (childState > result) { result = childState; } @@ -3136,18 +3141,6 @@ RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder, return result; } -LayerState -nsDisplayWrapList::RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder, - LayerManager* aManager, - const ContainerLayerParameters& aParameters, - const nsDisplayList& aList, - nsIFrame* aItemFrame) -{ - return RequiredLayerStateForChildrenInternal( - aBuilder, aManager, aParameters, aList, - nsLayoutUtils::GetAnimatedGeometryRootFor(aItemFrame)); -} - nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) { nsRect bounds; @@ -3324,7 +3317,8 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, if (NeedsActiveLayer()) return LAYER_ACTIVE; - return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mFrame); + return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, + nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder)); } bool @@ -4793,11 +4787,12 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder, return LAYER_ACTIVE; } - return mStoredList.RequiredLayerStateForChildren(aBuilder, - aManager, - aParameters, - *mStoredList.GetChildren(), - mFrame); + // Expect the child display items to have this frame as their animated + // geometry root (since it will be their reference frame). If they have a + // different animated geometry root, we'll make this an active layer so the + // animation can be accelerated. + return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, + *mStoredList.GetChildren(), Frame()); } bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder, diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 35429d89789a..7842d4dbe7f7 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2618,17 +2618,6 @@ public: return nullptr; } - /** - * Returns true if all descendant display items can be placed in the same - * ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE, - * and they all have the given aAnimatedGeometryRoot. - */ - static LayerState RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder, - LayerManager* aManager, - const ContainerLayerParameters& aParameters, - const nsDisplayList& aList, - nsIFrame* aItemFrame); - protected: nsDisplayWrapList() {} diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 4d4a0e408e40..3a646aa38e49 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1529,23 +1529,24 @@ nsLayoutUtils::IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame, nsRect* aDis return ViewportHasDisplayPort(aFrame->PresContext(), aDisplayPort); } -nsIFrame* -nsLayoutUtils::GetAnimatedGeometryRootFor(nsIFrame* aFrame, - const nsIFrame* aStopAtAncestor) +static nsIFrame* +GetAnimatedGeometryRootForFrame(nsIFrame* aFrame, + const nsIFrame* aStopAtAncestor) { nsIFrame* f = aFrame; nsIFrame* stickyFrame = nullptr; while (f != aStopAtAncestor) { - if (IsPopup(f)) + if (nsLayoutUtils::IsPopup(f)) break; if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f)) break; - if (!f->GetParent() && ViewportHasDisplayPort(f->PresContext())) { + 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 = GetCrossDocParentFrame(f); + nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f); if (!parent) break; nsIAtom* parentType = parent->GetType(); @@ -1576,7 +1577,7 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsIFrame* aFrame, } } // Fixed-pos frames are parented by the viewport frame, which has no parent - if (IsFixedPosFrameInDisplayPort(f)) { + if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) { return f; } f = parent; @@ -1593,7 +1594,7 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem, nsDisplayScrollLayer* scrollLayerItem = static_cast(aItem); nsIFrame* scrolledFrame = scrollLayerItem->GetScrolledFrame(); - return nsLayoutUtils::GetAnimatedGeometryRootFor(scrolledFrame, + return GetAnimatedGeometryRootForFrame(scrolledFrame, aBuilder->FindReferenceFrameFor(scrolledFrame)); } if (aItem->ShouldFixToViewport(aBuilder)) { @@ -1604,10 +1605,10 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem, nsIFrame* viewportFrame = nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame); NS_ASSERTION(viewportFrame, "no viewport???"); - return nsLayoutUtils::GetAnimatedGeometryRootFor(viewportFrame, + return GetAnimatedGeometryRootForFrame(viewportFrame, aBuilder->FindReferenceFrameFor(viewportFrame)); } - return nsLayoutUtils::GetAnimatedGeometryRootFor(f, aItem->ReferenceFrame()); + return GetAnimatedGeometryRootForFrame(f, aItem->ReferenceFrame()); } // static diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index c983c2a5561b..c6977cf6a2d1 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -474,28 +474,22 @@ public: nsRect* aDisplayPort = nullptr); /** - * Finds the nearest ancestor frame that is considered to have (or will have) - * "animated geometry". For example the scrolled frames of scrollframes which - * are actively being scrolled fall into this category. Frames with certain - * CSS properties that are being animated (e.g. 'left'/'top' etc) are also - * placed in this category. Frames with animated CSS transforms are not - * put in this category because they can be handled directly by - * nsDisplayTransform. - * Stop searching at aStopAtAncestor if there is no such ancestor before it - * in the ancestor chain. + * Finds the nearest ancestor frame to aItem that is considered to have (or + * will have) "animated geometry". For example the scrolled frames of + * scrollframes which are actively being scrolled fall into this category. + * Frames with certain CSS properties that are being animated (e.g. + * 'left'/'top' etc) are also placed in this category. * Frames with different active geometry roots are in different ThebesLayers, * so that we can animate the geometry root by changing its transform (either * on the main thread or in the compositor). - * This function is idempotent: a frame returned by GetAnimatedGeometryRootFor - * is always returned again if you pass it to GetAnimatedGeometryRootFor. + * The animated geometry root is required to be a descendant (or equal to) + * aItem's ReferenceFrame(), which means that we will fall back to + * returning aItem->ReferenceFrame() when we can't find another animated + * geometry root. */ - static nsIFrame* GetAnimatedGeometryRootFor(nsIFrame* aFrame, - const nsIFrame* aStopAtAncestor = nullptr); - static nsIFrame* GetAnimatedGeometryRootFor(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - /** * GetScrollableFrameFor returns the scrollable frame for a scrolled frame */