Bug 1512244 - Part 1: Cleanup DescendIntoChild r=mattwoodrow

Differential Revision: https://phabricator.services.mozilla.com/D13830

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Miko Mynttinen 2019-01-04 18:30:27 +00:00
parent 6fccd31719
commit b77e6dc486
4 changed files with 57 additions and 45 deletions

View File

@ -3352,44 +3352,38 @@ static nsDisplayItem* WrapInWrapList(nsDisplayListBuilder* aBuilder,
/**
* Check if a frame should be visited for building display list.
*/
static bool DescendIntoChild(nsDisplayListBuilder* aBuilder, nsIFrame* aChild,
const nsRect& aVisible, const nsRect& aDirty) {
nsIFrame* child = aChild;
const nsRect& dirty = aDirty;
if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
// No need to descend into child to catch placeholders for visible
// positioned stuff. So see if we can short-circuit frame traversal here.
// We can stop if child's frame subtree's intersection with the
// dirty area is empty.
// If the child is a scrollframe that we want to ignore, then we need
// to descend into it because its scrolled child may intersect the dirty
// area even if the scrollframe itself doesn't.
// There are cases where the "ignore scroll frame" on the builder is not set
// correctly, and so we additionally want to catch cases where the child is
// a root scrollframe and we are ignoring scrolling on the viewport.
nsIPresShell* shell = child->PresShell();
bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
(shell->IgnoringViewportScrolling() &&
child == shell->GetRootScrollFrame());
if (!keepDescending) {
nsRect childDirty;
if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()) &&
(!child->ForceDescendIntoIfVisible())) {
return false;
}
if (!childDirty.IntersectRect(aVisible, child->GetVisualOverflowRect())) {
return false;
}
// Usually we could set dirty to childDirty now but there's no
// benefit, and it can be confusing. It can especially confuse
// situations where we're going to ignore a scrollframe's clipping;
// we wouldn't want to clip the dirty area to the scrollframe's
// bounds in that case.
}
static bool DescendIntoChild(nsDisplayListBuilder* aBuilder,
const nsIFrame* aChild, const nsRect& aVisible,
const nsRect& aDirty) {
if (aChild->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) {
return true;
}
return true;
// If the child is a scrollframe that we want to ignore, then we need
// to descend into it because its scrolled child may intersect the dirty
// area even if the scrollframe itself doesn't.
if (aChild == aBuilder->GetIgnoreScrollFrame()) {
return true;
}
// There are cases where the "ignore scroll frame" on the builder is not set
// correctly, and so we additionally want to catch cases where the child is
// a root scrollframe and we are ignoring scrolling on the viewport.
if (aChild == aBuilder->GetPresShellIgnoreScrollFrame()) {
return true;
}
const nsRect overflow = aChild->GetVisualOverflowRect();
if (aDirty.Intersects(overflow)) {
return true;
}
if (aChild->ForceDescendIntoIfVisible() && aVisible.Intersects(overflow)) {
return true;
}
return false;
}
void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,

View File

@ -4033,7 +4033,7 @@ class nsIFrame : public nsQueryFrame {
bool HasDisplayItems();
bool HasDisplayItem(nsDisplayItem* aItem);
bool ForceDescendIntoIfVisible() { return mForceDescendIntoIfVisible; }
bool ForceDescendIntoIfVisible() const { return mForceDescendIntoIfVisible; }
void SetForceDescendIntoIfVisible(bool aForce) {
mForceDescendIntoIfVisible = aForce;
}

View File

@ -1349,20 +1349,28 @@ void nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
}
state->mInsidePointerEventsNoneDoc = pointerEventsNone;
if (!buildCaret) return;
RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
if (state->mCaretFrame) {
MarkFrameForDisplay(state->mCaretFrame, aReferenceFrame);
}
state->mPresShellIgnoreScrollFrame =
state->mPresShell->IgnoringViewportScrolling()
? state->mPresShell->GetRootScrollFrame()
: nullptr;
nsPresContext* pc = aReferenceFrame->PresContext();
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
if (docShell) {
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
}
mIsInChromePresContext = pc->IsChrome();
if (!buildCaret) {
return;
}
RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
if (state->mCaretFrame) {
MarkFrameForDisplay(state->mCaretFrame, aReferenceFrame);
}
}
// A non-blank paint is a paint that does not just contain the canvas

View File

@ -797,6 +797,15 @@ class nsDisplayListBuilder {
* Get the caret associated with the current presshell.
*/
nsCaret* GetCaret();
/**
* Returns the root scroll frame for the current PresShell, if the PresShell
* is ignoring viewport scrolling.
*/
nsIFrame* GetPresShellIgnoreScrollFrame() {
return CurrentPresShellState()->mPresShellIgnoreScrollFrame;
}
/**
* Notify the display list builder that we're entering a presshell.
* aReferenceFrame should be a frame in the new presshell.
@ -1833,6 +1842,7 @@ class nsDisplayListBuilder {
// in the document, and is set when we enter a subdocument for a pointer-
// events:none frame.
bool mInsidePointerEventsNoneDoc;
nsIFrame* mPresShellIgnoreScrollFrame;
};
PresShellState* CurrentPresShellState() {