зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1263349 (Part 2) - Cache the current scroll parent and information about scrollports and displayports on nsDisplayListBuilder. r=botond,mstange
This commit is contained in:
Родитель
41d7cfb3d3
Коммит
1cb3c53e11
|
@ -670,6 +670,72 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
|
|||
aLayer, data, pending);
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter::
|
||||
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aScrollParent)
|
||||
: mBuilder(aBuilder)
|
||||
, mOldScrollParent(aBuilder->mCurrentScrollParent)
|
||||
, mOldDisplayPortConsideringAncestors(aBuilder->mDisplayPortConsideringAncestors)
|
||||
, mOldScrollPortConsideringAncestors(aBuilder->mScrollPortConsideringAncestors)
|
||||
, mOldScrollParentId(aBuilder->mCurrentScrollParentId)
|
||||
, mOldForceLayer(aBuilder->mForceLayerForScrollParent)
|
||||
, mChangedSubtrees(false)
|
||||
{
|
||||
aBuilder->UpdateCurrentScrollParent(aScrollParent);
|
||||
Init();
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter::
|
||||
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder,
|
||||
const OutOfFlowDisplayData* aOutOfFlowData)
|
||||
: mBuilder(aBuilder)
|
||||
, mOldScrollParent(aBuilder->mCurrentScrollParent)
|
||||
, mOldDisplayPortConsideringAncestors(aBuilder->mDisplayPortConsideringAncestors)
|
||||
, mOldScrollPortConsideringAncestors(aBuilder->mScrollPortConsideringAncestors)
|
||||
, mOldScrollParentId(aBuilder->mCurrentScrollParentId)
|
||||
, mOldForceLayer(aBuilder->mForceLayerForScrollParent)
|
||||
, mChangedSubtrees(true)
|
||||
{
|
||||
aBuilder->UpdateCurrentScrollParentForOutOfFlow(aOutOfFlowData);
|
||||
Init();
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter::Init()
|
||||
{
|
||||
// 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 = mOldScrollParentId != mBuilder->mCurrentScrollParentId;
|
||||
|
||||
mBuilder->mForceLayerForScrollParent = false;
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter::
|
||||
~AutoCurrentScrollParentIdSetter()
|
||||
{
|
||||
mBuilder->mCurrentScrollParent = mOldScrollParent;
|
||||
mBuilder->mDisplayPortConsideringAncestors = mOldDisplayPortConsideringAncestors;
|
||||
mBuilder->mScrollPortConsideringAncestors = mOldScrollPortConsideringAncestors;
|
||||
mBuilder->mCurrentScrollParentId = mOldScrollParentId;
|
||||
|
||||
if (mCanBeScrollParent || mChangedSubtrees) {
|
||||
// If |mCanBeScrollParent| is set, caller code is responsible for
|
||||
// having dealt with the current value of
|
||||
// mBuilder->mForceLayerForScrollParent, so we can just restore the
|
||||
// old value. If |mChangedSubtrees| is set, we don't propagate the
|
||||
// flag because it doesn't make sense to propagate it through
|
||||
// unrelated subtrees.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
nsDisplayListBuilderMode aMode, bool aBuildCaret)
|
||||
: mReferenceFrame(aReferenceFrame),
|
||||
|
@ -685,6 +751,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|||
mGlassDisplayItem(nullptr),
|
||||
mScrollInfoItemsForHoisting(nullptr),
|
||||
mMode(aMode),
|
||||
mCurrentScrollParent(nullptr),
|
||||
mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
|
||||
mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
|
||||
mCurrentScrollbarFlags(0),
|
||||
|
@ -732,6 +799,9 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|||
|
||||
mFrameToAnimatedGeometryRootMap.Put(aReferenceFrame, &mRootAGR);
|
||||
|
||||
UpdateCurrentScrollParent(
|
||||
nsLayoutUtils::GetAsyncScrollableProperAncestorFrameOrFallback(aReferenceFrame));
|
||||
|
||||
nsCSSRendering::BeginFrameTreesLocked();
|
||||
PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX < (1 << nsDisplayItem::TYPE_BITS));
|
||||
}
|
||||
|
@ -854,7 +924,12 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
|
|||
|
||||
const DisplayItemClip* oldClip = mClipState.GetClipForContainingBlockDescendants();
|
||||
const DisplayItemScrollClip* sc = mClipState.GetCurrentInnermostScrollClip();
|
||||
OutOfFlowDisplayData* data = new OutOfFlowDisplayData(oldClip, sc, dirty);
|
||||
OutOfFlowDisplayData* data =
|
||||
new OutOfFlowDisplayData(oldClip, sc, dirty,
|
||||
mCurrentScrollParent, mCurrentScrollParentId,
|
||||
mDisplayPortConsideringAncestors,
|
||||
mScrollPortConsideringAncestors);
|
||||
|
||||
aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
|
||||
|
||||
MarkFrameForDisplay(aFrame, aDirtyFrame);
|
||||
|
@ -1221,6 +1296,132 @@ nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame)
|
|||
return cursor;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::UpdateCurrentScrollParent(nsIFrame* aScrollParent)
|
||||
{
|
||||
// If the new scroll parent is the same as the old scroll parent, we don't
|
||||
// have to do anything. This can happen because we sometimes instantiate an
|
||||
// AutoCurrentScrollParentIdSetter unconditionally but only pass it a new
|
||||
// scroll parent if certain conditions are true.
|
||||
if (aScrollParent == mCurrentScrollParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the current scroll parent.
|
||||
nsIFrame* oldScrollParent = mCurrentScrollParent;
|
||||
mCurrentScrollParent = aScrollParent;
|
||||
|
||||
// If there's no scroll parent now (which may be true because we're
|
||||
// initializing this nsDisplayListBuilder for the first time, or because
|
||||
// we're in a strange state where there's no pres shell or no root frame)
|
||||
// then we just reset everything to its initial values.
|
||||
if (!aScrollParent) {
|
||||
mDisplayPortConsideringAncestors = nsRect();
|
||||
mScrollPortConsideringAncestors = nsRect();
|
||||
mCurrentScrollParentId = FrameMetrics::NULL_SCROLL_ID;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the new scroll parent ID.
|
||||
nsIContent* content = aScrollParent->GetContent();
|
||||
mCurrentScrollParentId = content ? nsLayoutUtils::FindOrCreateIDFor(content)
|
||||
: FrameMetrics::NULL_SCROLL_ID;
|
||||
|
||||
nsIScrollableFrame* newScrollParent = do_QueryFrame(aScrollParent);
|
||||
if (!newScrollParent) {
|
||||
// There's no scrollable parent frame, so we've been forced to fall back
|
||||
// to the root frame. (Most likely this is a XUL document.) Just use its
|
||||
// size for both the displayport and the scrollport.
|
||||
MOZ_ASSERT(!oldScrollParent, "Falling back to the root frame when an ancestor "
|
||||
"scrollable frame existed?");
|
||||
nsRect frameRect(nsPoint(0, 0), aScrollParent->GetSize());
|
||||
mDisplayPortConsideringAncestors = frameRect;
|
||||
mScrollPortConsideringAncestors = frameRect;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCurrentScrollParentId != FrameMetrics::NULL_SCROLL_ID,
|
||||
"Couldn't get a scroll ID for a scrollable frame?");
|
||||
|
||||
// If we didn't have a scroll parent before, but we do now, the displayport
|
||||
// and scrollport we're tracking are just those of the new scroll parent.
|
||||
if (!oldScrollParent) {
|
||||
mDisplayPortConsideringAncestors =
|
||||
nsLayoutUtils::GetDisplayPortOrFallbackToScrollPort(newScrollParent);
|
||||
mScrollPortConsideringAncestors = newScrollParent->GetScrollPortRect();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsIScrollableFrame* oldScrollableParent = do_QueryFrame(oldScrollParent);
|
||||
if (oldScrollableParent && oldScrollableParent->WantAsyncScroll()) {
|
||||
// Normally, the old scroll parent should be the nearest async
|
||||
// scrollable ancestor of the new scroll parent.
|
||||
MOZ_ASSERT(nsLayoutUtils::GetAsyncScrollableProperAncestorFrame(aScrollParent) ==
|
||||
oldScrollableParent);
|
||||
} else {
|
||||
// If the old scroll parent isn't async scrollable or isn't scrollable
|
||||
// at all, (e.g., because we had to fall back to the root frame in a XUL
|
||||
// document) then at least assert it's an ancestor of the new scroll parent.
|
||||
MOZ_ASSERT(nsLayoutUtils::IsProperAncestorFrameCrossDoc(oldScrollParent,
|
||||
aScrollParent));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If the effective displayport, considering ancestors, is already empty, we
|
||||
// can bail early as we know the intersection checks below will fail.
|
||||
if (mDisplayPortConsideringAncestors.IsEmpty()) {
|
||||
mDisplayPortConsideringAncestors = nsRect();
|
||||
mScrollPortConsideringAncestors = nsRect();
|
||||
return;
|
||||
}
|
||||
|
||||
// The entire displayport for this subtree is the critical displayport of
|
||||
// this scroll parent if any part of it is visible within the previous scroll
|
||||
// parent's critical displayport. (What we're trying to do is capture
|
||||
// everything that APZ could asynchronously scroll into view.) If it isn't
|
||||
// visible, then the displayport for this subtree is empty and the
|
||||
// scrollport, trivially, is too.
|
||||
nsRect displayPort =
|
||||
nsLayoutUtils::GetDisplayPortOrFallbackToScrollPort(newScrollParent);
|
||||
nsRect displayPortIntersection =
|
||||
nsLayoutUtils::TransformAndIntersectRect(oldScrollParent,
|
||||
mDisplayPortConsideringAncestors,
|
||||
aScrollParent,
|
||||
displayPort);
|
||||
if (displayPortIntersection.IsEmpty()) {
|
||||
mDisplayPortConsideringAncestors = nsRect();
|
||||
mScrollPortConsideringAncestors = nsRect();
|
||||
return;
|
||||
}
|
||||
|
||||
// See above: we take the whole thing, not the intersection with the
|
||||
// previous scroll parent's critical displayport.
|
||||
mDisplayPortConsideringAncestors = displayPort;
|
||||
|
||||
// The scrollport for this subtree is the intersection of aScrollParent's
|
||||
// scrollport with all ancestor scrollports.
|
||||
mScrollPortConsideringAncestors =
|
||||
nsLayoutUtils::TransformAndIntersectRect(oldScrollParent,
|
||||
mScrollPortConsideringAncestors,
|
||||
aScrollParent,
|
||||
newScrollParent->GetScrollPortRect());
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::UpdateCurrentScrollParentForOutOfFlow(const OutOfFlowDisplayData* aOutOfFlowData)
|
||||
{
|
||||
MOZ_ASSERT(aOutOfFlowData);
|
||||
|
||||
// Just set the information from |aOutOfFlowData| unconditionally.
|
||||
mCurrentScrollParent = aOutOfFlowData->mCurrentScrollParent;
|
||||
mCurrentScrollParentId = aOutOfFlowData->mCurrentScrollParentId;
|
||||
mDisplayPortConsideringAncestors = aOutOfFlowData->mDisplayPortConsideringAncestors;
|
||||
mScrollPortConsideringAncestors = aOutOfFlowData->mScrollPortConsideringAncestors;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
|
||||
{
|
||||
|
|
|
@ -368,6 +368,30 @@ public:
|
|||
* Get the scrollframe to ignore, if any.
|
||||
*/
|
||||
nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
|
||||
/**
|
||||
* Get the nearest ancestor scrollframe, or the root frame if there is no
|
||||
* ancestor scrollframe, or null if neither exists.
|
||||
*/
|
||||
nsIFrame* GetCurrentScrollParent() { return mCurrentScrollParent; }
|
||||
/**
|
||||
* Get the critical displayport of the nearest ancestor scrollframe, in the
|
||||
* coordinate system of the frame returned by GetCurrentScrollParent(). If
|
||||
* the ancestor scrollframe's critical displayport does not intersect the
|
||||
* critical displayport of the scrollframe that encloses it, and so on
|
||||
* transitively up the frame tree, returns the empty rect. The idea is that
|
||||
* this method considers a displayport visible if its nearest ancestor is
|
||||
* visible and some part of it intersects its nearest ancestor, which means
|
||||
* that we capture everything that APZ could asynchronously scroll into
|
||||
* view. Used for visibility tracking during painting.
|
||||
*/
|
||||
nsRect GetDisplayPortConsideringAncestors() { return mDisplayPortConsideringAncestors; }
|
||||
/**
|
||||
* Get the intersection of all ancestor scrollframes' scrollports. Used for
|
||||
* visibility tracking during painting. Unlike the displayport case, for
|
||||
* scrollports we use strict intersection, because we only want to detect
|
||||
* frames that are actually visible in the viewport.
|
||||
*/
|
||||
nsRect GetScrollPortConsideringAncestors() { return mScrollPortConsideringAncestors; }
|
||||
/**
|
||||
* Get the ViewID of the nearest scrolling ancestor frame.
|
||||
*/
|
||||
|
@ -826,49 +850,64 @@ public:
|
|||
uint32_t mCachedItemIndex;
|
||||
};
|
||||
|
||||
struct OutOfFlowDisplayData;
|
||||
|
||||
/**
|
||||
* A helper class to temporarily set the value of mCurrentScrollParentId.
|
||||
* A helper class to temporarily set the value of mCurrentScrollParentId and
|
||||
* cache information about the effective displayport and scrollport,
|
||||
* considering all ancestor scrollframes. See
|
||||
* GetDisplayPortConsideringAncestors() and
|
||||
* GetScrollPortConsideringAncestors() for the details.
|
||||
*/
|
||||
class AutoCurrentScrollParentIdSetter;
|
||||
friend class AutoCurrentScrollParentIdSetter;
|
||||
class AutoCurrentScrollParentIdSetter {
|
||||
public:
|
||||
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollId)
|
||||
: 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;
|
||||
}
|
||||
/**
|
||||
* Temporarily update the cached scroll parent information on @aBuilder
|
||||
* from frame @aFrame. @aFrame should be a a scrollframe that is a
|
||||
* descendant of @aBuilder's current scroll parent. (The exception is if
|
||||
* there's no current scroll parent, in which case @aFrame does not have to
|
||||
* be a scrollframe; this is fallback behavior for XUL documents, which
|
||||
* may not have a root scrollframe.)
|
||||
*
|
||||
* If @aNewScrollParentFrom is SCROLLFRAMES_ON_PATH_TO_ROOT, @aFrame is
|
||||
* interpreted as a scrollframe in a different subtree. In this case we
|
||||
* have to walk up the frame tree all the way to the root to gather
|
||||
* information about the effective displayport and scrollport.
|
||||
*/
|
||||
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aScrollParent);
|
||||
|
||||
/**
|
||||
* Temporarily updated the cached scroll parent information on @aBuilder
|
||||
* from saved information on @aOutOfFlowData. This is necessary when
|
||||
* traversing out-of-flow frames via their placeholder frames, since their
|
||||
* scroll parent may not be the same as the scroll parent of the
|
||||
* placeholder frame.
|
||||
*/
|
||||
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder,
|
||||
const OutOfFlowDisplayData* aOutOfFlowData);
|
||||
|
||||
~AutoCurrentScrollParentIdSetter();
|
||||
|
||||
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:
|
||||
void Init();
|
||||
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
ViewID mOldValue;
|
||||
bool mOldForceLayer;
|
||||
bool mCanBeScrollParent;
|
||||
nsIFrame* mOldScrollParent;
|
||||
nsRect mOldDisplayPortConsideringAncestors;
|
||||
nsRect mOldScrollPortConsideringAncestors;
|
||||
ViewID mOldScrollParentId;
|
||||
bool mOldForceLayer : 1;
|
||||
bool mCanBeScrollParent : 1;
|
||||
bool mChangedSubtrees : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -989,14 +1028,26 @@ public:
|
|||
struct OutOfFlowDisplayData {
|
||||
OutOfFlowDisplayData(const DisplayItemClip* aContainingBlockClip,
|
||||
const DisplayItemScrollClip* aContainingBlockScrollClip,
|
||||
const nsRect &aDirtyRect)
|
||||
const nsRect& aDirtyRect,
|
||||
nsIFrame* aCurrentScrollParent,
|
||||
ViewID aCurrentScrollParentId,
|
||||
const nsRect& aDisplayPortConsideringAncestors,
|
||||
const nsRect& aScrollPortConsideringAncestors)
|
||||
: mContainingBlockClip(aContainingBlockClip ? *aContainingBlockClip : DisplayItemClip())
|
||||
, mContainingBlockScrollClip(aContainingBlockScrollClip)
|
||||
, mDirtyRect(aDirtyRect)
|
||||
, mCurrentScrollParent(aCurrentScrollParent)
|
||||
, mCurrentScrollParentId(aCurrentScrollParentId)
|
||||
, mDisplayPortConsideringAncestors(aDisplayPortConsideringAncestors)
|
||||
, mScrollPortConsideringAncestors(aScrollPortConsideringAncestors)
|
||||
{}
|
||||
DisplayItemClip mContainingBlockClip;
|
||||
const DisplayItemScrollClip* mContainingBlockScrollClip;
|
||||
nsRect mDirtyRect;
|
||||
nsIFrame* mCurrentScrollParent;
|
||||
ViewID mCurrentScrollParentId;
|
||||
nsRect mDisplayPortConsideringAncestors;
|
||||
nsRect mScrollPortConsideringAncestors;
|
||||
};
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
|
||||
|
@ -1153,6 +1204,23 @@ private:
|
|||
*/
|
||||
nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Updates cached information about the nearest ancestor scrollable frame.
|
||||
* @aScrollParent should be a descendant of the previous nearest ancestor
|
||||
* scrollable frame. @aScrollParent may be null, indicating that there is
|
||||
* no ancestor scrollable frame.
|
||||
*/
|
||||
void UpdateCurrentScrollParent(nsIFrame* aScrollParent);
|
||||
|
||||
/**
|
||||
* Updates cached information about the nearest ancestor scrollable frame.
|
||||
* The new information is read from @aOutOfFlowData, and unconditionally
|
||||
* replaces the cached information without reference to the current scroll
|
||||
* parent, since we're descending into an out-of-flow frame that does not
|
||||
* necessarily have the same scroll parent chain.
|
||||
*/
|
||||
void UpdateCurrentScrollParentForOutOfFlow(const OutOfFlowDisplayData* aOutOfFlowData);
|
||||
|
||||
friend class nsDisplayCanvasBackgroundImage;
|
||||
friend class nsDisplayBackgroundImage;
|
||||
friend class nsDisplayFixedPosition;
|
||||
|
@ -1250,7 +1318,10 @@ private:
|
|||
nsTArray<DisplayItemScrollClip*> mScrollClipsToDestroy;
|
||||
nsTArray<DisplayItemClip*> mDisplayItemClipsToDestroy;
|
||||
nsDisplayListBuilderMode mMode;
|
||||
nsIFrame* mCurrentScrollParent;
|
||||
ViewID mCurrentScrollParentId;
|
||||
nsRect mDisplayPortConsideringAncestors;
|
||||
nsRect mScrollPortConsideringAncestors;
|
||||
ViewID mCurrentScrollbarTarget;
|
||||
uint32_t mCurrentScrollbarFlags;
|
||||
Preserves3DContext mPreserves3DCtx;
|
||||
|
|
|
@ -3534,34 +3534,6 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
builder.EnterPresShell(aFrame);
|
||||
nsRect dirtyRect = visibleRegion.GetBounds();
|
||||
{
|
||||
// If a scrollable container layer is created in nsDisplayList::PaintForFrame,
|
||||
// it will be the scroll parent for display items that are built in the
|
||||
// BuildDisplayListForStackingContext call below. We need to set the scroll
|
||||
// parent on the display list builder while we build those items, so that they
|
||||
// can pick up their scroll parent's id.
|
||||
ViewID id = FrameMetrics::NULL_SCROLL_ID;
|
||||
if (ignoreViewportScrolling && presContext->IsRootContentDocument()) {
|
||||
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
|
||||
if (nsIContent* content = rootScrollFrame->GetContent()) {
|
||||
id = nsLayoutUtils::FindOrCreateIDFor(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
|
||||
else if (presShell->GetDocument() && presShell->GetDocument()->IsRootDisplayDocument()
|
||||
&& !presShell->GetRootScrollFrame()) {
|
||||
// In cases where the root document is a XUL document, we want to take
|
||||
// the ViewID from the root element, as that will be the ViewID of the
|
||||
// root APZC in the tree. Skip doing this in cases where we know
|
||||
// nsGfxScrollFrame::BuilDisplayList will do it instead.
|
||||
if (dom::Element* element = presShell->GetDocument()->GetDocumentElement()) {
|
||||
id = nsLayoutUtils::FindOrCreateIDFor(element);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
|
||||
|
||||
PROFILER_LABEL("nsLayoutUtils", "PaintFrame::BuildDisplayList",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
|
|
|
@ -2782,11 +2782,17 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
|
||||
CheckForApzAwareEventHandlers(aBuilder, child);
|
||||
|
||||
Maybe<nsDisplayListBuilder::AutoCurrentScrollParentIdSetter> idSetter;
|
||||
if (savedOutOfFlowData) {
|
||||
clipState.SetClipForContainingBlockDescendants(
|
||||
&savedOutOfFlowData->mContainingBlockClip);
|
||||
clipState.SetScrollClipForContainingBlockDescendants(
|
||||
savedOutOfFlowData->mContainingBlockScrollClip);
|
||||
|
||||
// For out-of-flow frames, the current scroll parent is wrong, because it's
|
||||
// the scroll parent for the placeholder frame rather than the actual
|
||||
// out-of-flow frame, so we need to update the current scroll parent.
|
||||
idSetter.emplace(aBuilder, savedOutOfFlowData);
|
||||
} else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
|
||||
isPlaceholder) {
|
||||
// If we have nested out-of-flow frames and the outer one isn't visible
|
||||
|
|
|
@ -3299,11 +3299,11 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// parent. This is intentional because that is what happens for positioned children
|
||||
// of scroll layers, and we want to maintain consistent behaviour between scroll layers
|
||||
// and scroll info layers.
|
||||
nsIContent* content = couldBuildLayer ? mScrolledFrame->GetContent()
|
||||
: nullptr;
|
||||
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
|
||||
aBuilder,
|
||||
couldBuildLayer && mScrolledFrame->GetContent()
|
||||
? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent())
|
||||
: aBuilder->GetCurrentScrollParentId());
|
||||
aBuilder, content ? mOuter : aBuilder->GetCurrentScrollParent());
|
||||
|
||||
nsRect clipRect = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
|
||||
// Our override of GetBorderRadii ensures we never have a radius at
|
||||
|
|
|
@ -483,11 +483,12 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
if (subdocRootFrame) {
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
nsIContent* content = ignoreViewportScrolling && rootScrollFrame
|
||||
? rootScrollFrame->GetContent()
|
||||
: nullptr;
|
||||
|
||||
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
|
||||
aBuilder,
|
||||
ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
|
||||
? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
|
||||
: aBuilder->GetCurrentScrollParentId());
|
||||
aBuilder, content ? rootScrollFrame : aBuilder->GetCurrentScrollParent());
|
||||
|
||||
aBuilder->SetAncestorHasApzAwareEventHandler(false);
|
||||
subdocRootFrame->
|
||||
|
|
Загрузка…
Ссылка в новой задаче