Skip to content

Commit

Permalink
Bug 1102427 - Ensure scroll parents of an active scrollframe are laye…
Browse files Browse the repository at this point in the history
…rized.
  • Loading branch information
rmottola committed Feb 20, 2019
1 parent f671753 commit 910d43e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
3 changes: 2 additions & 1 deletion layout/base/nsDisplayList.cpp
Expand Up @@ -590,7 +590,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mAncestorHasApzAwareEventHandler(false),
mHaveScrollableDisplayPort(false),
mWindowDraggingAllowed(false),
mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame))
mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
mForceLayerForScrollParent(false)
{
MOZ_COUNT_CTOR(nsDisplayListBuilder);
PL_InitArenaPool(&mPool, "displayListArena", 1024,
Expand Down
36 changes: 35 additions & 1 deletion layout/base/nsDisplayList.h
Expand Up @@ -253,6 +253,13 @@ class nsDisplayListBuilder {
* Get the ViewID of the nearest scrolling ancestor frame.
*/
ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; }
/**
* Get and set the flag that indicates if scroll parents should have layers
* forcibly created. This flag is set when a deeply nested scrollframe has
* a displayport, and for scroll handoff to work properly the ancestor
* scrollframes should also get their own scrollable layers.
*/
void ForceLayerForScrollParent() { mForceLayerForScrollParent = true; }
/**
* Get the ViewID and the scrollbar flags corresponding to the scrollbar for
* which we are building display items at the moment.
Expand Down Expand Up @@ -660,15 +667,41 @@ class nsDisplayListBuilder {
class AutoCurrentScrollParentIdSetter {
public:
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollId)
: mBuilder(aBuilder), mOldValue(aBuilder->mCurrentScrollParentId) {
: mBuilder(aBuilder)
, mOldValue(aBuilder->mCurrentScrollParentId)
, mOldForceLayer(aBuilder->mForceLayerForScrollParent) {
// If this AutoCurrentScrollParentIdSetter has the same scrollId as the
// previous one on the stack, then that means the scrollframe that
// created this isn't actually scrollable and cannot participate in
// scroll handoff. We set mCanBeScrollParent to false to indicate this.
mCanBeScrollParent = (mOldValue != aScrollId);
aBuilder->mCurrentScrollParentId = aScrollId;
aBuilder->mForceLayerForScrollParent = false;
}
bool ShouldForceLayerForScrollParent() const {
// Only scrollframes participating in scroll handoff can be forced to
// layerize
return mCanBeScrollParent && mBuilder->mForceLayerForScrollParent;
};
~AutoCurrentScrollParentIdSetter() {
mBuilder->mCurrentScrollParentId = mOldValue;
if (mCanBeScrollParent) {
// If this flag is set, caller code is responsible for having dealt
// with the current value of mBuilder->mForceLayerForScrollParent, so
// we can just restore the old value.
mBuilder->mForceLayerForScrollParent = mOldForceLayer;
} else {
// Otherwise we need to keep propagating the force-layerization flag
// upwards to the next ancestor scrollframe that does participate in
// scroll handoff.
mBuilder->mForceLayerForScrollParent |= mOldForceLayer;
}
}
private:
nsDisplayListBuilder* mBuilder;
ViewID mOldValue;
bool mOldForceLayer;
bool mCanBeScrollParent;
};

/**
Expand Down Expand Up @@ -919,6 +952,7 @@ class nsDisplayListBuilder {
bool mHaveScrollableDisplayPort;
bool mWindowDraggingAllowed;
bool mIsBuildingForPopup;
bool mForceLayerForScrollParent;
};

class nsDisplayItem;
Expand Down
16 changes: 16 additions & 0 deletions layout/generic/nsGfxScrollFrame.cpp
Expand Up @@ -3108,6 +3108,22 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}

mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, scrolledContent);

if (idSetter.ShouldForceLayerForScrollParent() &&
!gfxPrefs::LayoutUseContainersForRootFrames())
{
// Note that forcing layerization of scroll parents follows the scroll
// handoff chain which is subject to the out-of-flow-frames caveat noted
// above (where the idSetter variable is created).
//
// This is not compatible when using containes for root scrollframes.
MOZ_ASSERT(shouldBuildLayer && mScrolledFrame->GetContent());
mShouldBuildScrollableLayer = true;
}
}

if (mShouldBuildScrollableLayer && !gfxPrefs::LayoutUseContainersForRootFrames()) {
aBuilder->ForceLayerForScrollParent();
}

if (MOZ_UNLIKELY(mOuter->StyleDisplay()->mOverflowClipBox ==
Expand Down

0 comments on commit 910d43e

Please sign in to comment.