mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-21 14:47:31 +09:00
Issue #1355 - Avoid unnecessary work in nsIFrame::BuildDisplayListForStackingContext() and nsIFrame::BuildDisplayListForChild() and Cleanup DescendIntoChild
Bug 1441796 - Part 1: Optimize the (pseudo)-stacking context conditions Bug 1441796 - Part 3: Reuse the results in nsIFrame::BuildDisplayListForStackingContext() for ChildrenHavePerspective(), IsTransformed(), and Combines3DTransformWithAncestors() Bug 1512244 - Part 1: Cleanup DescendIntoChild
This commit is contained in:
parent
e15b1ba0ec
commit
da0e3a828b
3 changed files with 80 additions and 57 deletions
|
|
@ -1009,8 +1009,22 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
|
||||||
}
|
}
|
||||||
state->mInsidePointerEventsNoneDoc = pointerEventsNone;
|
state->mInsidePointerEventsNoneDoc = pointerEventsNone;
|
||||||
|
|
||||||
if (!buildCaret)
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
|
RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
|
||||||
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
|
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
|
||||||
|
|
@ -1018,13 +1032,6 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
|
||||||
mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
|
mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
|
||||||
MarkFrameForDisplay(state->mCaretFrame, nullptr);
|
MarkFrameForDisplay(state->mCaretFrame, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPresContext* pc = aReferenceFrame->PresContext();
|
|
||||||
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
|
|
||||||
if (docShell) {
|
|
||||||
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
|
||||||
}
|
|
||||||
mIsInChromePresContext = pc->IsChrome();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A non-blank paint is a paint that does not just contain the canvas background.
|
// A non-blank paint is a paint that does not just contain the canvas background.
|
||||||
|
|
|
||||||
|
|
@ -520,6 +520,14 @@ public:
|
||||||
* Get the caret associated with the current presshell.
|
* Get the caret associated with the current presshell.
|
||||||
*/
|
*/
|
||||||
nsCaret* GetCaret();
|
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.
|
* Notify the display list builder that we're entering a presshell.
|
||||||
* aReferenceFrame should be a frame in the new presshell.
|
* aReferenceFrame should be a frame in the new presshell.
|
||||||
|
|
@ -805,10 +813,11 @@ public:
|
||||||
friend class AutoSaveRestorePerspectiveIndex;
|
friend class AutoSaveRestorePerspectiveIndex;
|
||||||
class AutoSaveRestorePerspectiveIndex {
|
class AutoSaveRestorePerspectiveIndex {
|
||||||
public:
|
public:
|
||||||
AutoSaveRestorePerspectiveIndex(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
AutoSaveRestorePerspectiveIndex(nsDisplayListBuilder* aBuilder,
|
||||||
|
const bool aChildrenHavePerspective)
|
||||||
: mBuilder(nullptr)
|
: mBuilder(nullptr)
|
||||||
{
|
{
|
||||||
if (aFrame->ChildrenHavePerspective()) {
|
if (aChildrenHavePerspective) {
|
||||||
mBuilder = aBuilder;
|
mBuilder = aBuilder;
|
||||||
mCachedItemIndex = aBuilder->mPerspectiveItemIndex;
|
mCachedItemIndex = aBuilder->mPerspectiveItemIndex;
|
||||||
aBuilder->mPerspectiveItemIndex = 0;
|
aBuilder->mPerspectiveItemIndex = 0;
|
||||||
|
|
@ -1175,6 +1184,7 @@ private:
|
||||||
nsRect mCaretRect;
|
nsRect mCaretRect;
|
||||||
uint32_t mFirstFrameMarkedForDisplay;
|
uint32_t mFirstFrameMarkedForDisplay;
|
||||||
bool mIsBackgroundOnly;
|
bool mIsBackgroundOnly;
|
||||||
|
nsIFrame* mPresShellIgnoreScrollFrame;
|
||||||
// This is a per-document flag turning off event handling for all content
|
// This is a per-document flag turning off event handling for all content
|
||||||
// in the document, and is set when we enter a subdocument for a pointer-
|
// in the document, and is set when we enter a subdocument for a pointer-
|
||||||
// events:none frame.
|
// events:none frame.
|
||||||
|
|
|
||||||
|
|
@ -2120,9 +2120,14 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
aBuilder->AddToWillChangeBudget(this, GetSize());
|
aBuilder->AddToWillChangeBudget(this, GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extend3DContext = Extend3DContext();
|
const bool isTransformed = IsTransformed();
|
||||||
|
const bool hasPerspective = isTransformed && HasPerspective();
|
||||||
|
const bool extend3DContext = Extend3DContext();
|
||||||
|
const bool combines3DTransformWithAncestors =
|
||||||
|
(extend3DContext || isTransformed) && Combines3DTransformWithAncestors();
|
||||||
|
const bool childrenHavePerspective = ChildrenHavePerspective();
|
||||||
Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
|
Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
|
||||||
if (extend3DContext && !Combines3DTransformWithAncestors()) {
|
if (extend3DContext && !combines3DTransformWithAncestors) {
|
||||||
// Start a new preserves3d context to keep informations on
|
// Start a new preserves3d context to keep informations on
|
||||||
// nsDisplayListBuilder.
|
// nsDisplayListBuilder.
|
||||||
autoPreserves3DContext.emplace(aBuilder);
|
autoPreserves3DContext.emplace(aBuilder);
|
||||||
|
|
@ -2136,9 +2141,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
// the chain.
|
// the chain.
|
||||||
nsRect dirtyRect = aBuilder->GetDirtyRect();
|
nsRect dirtyRect = aBuilder->GetDirtyRect();
|
||||||
|
|
||||||
bool inTransform = aBuilder->IsInTransform();
|
|
||||||
bool isTransformed = IsTransformed();
|
|
||||||
bool hasPerspective = HasPerspective();
|
|
||||||
// reset blend mode so we can keep track if this stacking context needs have
|
// reset blend mode so we can keep track if this stacking context needs have
|
||||||
// a nsDisplayBlendContainer. Set the blend mode back when the routine exits
|
// a nsDisplayBlendContainer. Set the blend mode back when the routine exits
|
||||||
// so we keep track if the parent stacking context needs a container too.
|
// so we keep track if the parent stacking context needs a container too.
|
||||||
|
|
@ -2146,6 +2148,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
aBuilder->SetContainsBlendMode(false);
|
aBuilder->SetContainsBlendMode(false);
|
||||||
|
|
||||||
nsRect dirtyRectOutsideTransform = dirtyRect;
|
nsRect dirtyRectOutsideTransform = dirtyRect;
|
||||||
|
bool inTransform = aBuilder->IsInTransform();
|
||||||
if (isTransformed) {
|
if (isTransformed) {
|
||||||
const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
|
const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
|
||||||
if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder,
|
if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder,
|
||||||
|
|
@ -2158,7 +2161,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
|
|
||||||
// If we're in preserve-3d then grab the dirty rect that was given to the root
|
// If we're in preserve-3d then grab the dirty rect that was given to the root
|
||||||
// and transform using the combined transform.
|
// and transform using the combined transform.
|
||||||
if (Combines3DTransformWithAncestors()) {
|
if (combines3DTransformWithAncestors) {
|
||||||
dirtyRect = aBuilder->GetPreserves3DRects();
|
dirtyRect = aBuilder->GetPreserves3DRects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2273,7 +2276,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
nsDisplayListBuilder::AutoInTransformSetter
|
nsDisplayListBuilder::AutoInTransformSetter
|
||||||
inTransformSetter(aBuilder, inTransform);
|
inTransformSetter(aBuilder, inTransform);
|
||||||
nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
|
nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
|
||||||
perspectiveIndex(aBuilder, this);
|
perspectiveIndex(aBuilder, childrenHavePerspective);
|
||||||
|
|
||||||
CheckForApzAwareEventHandlers(aBuilder, this);
|
CheckForApzAwareEventHandlers(aBuilder, this);
|
||||||
|
|
||||||
|
|
@ -2597,6 +2600,35 @@ WrapInWrapList(nsDisplayListBuilder* aBuilder,
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool DescendIntoChild(nsDisplayListBuilder* aBuilder,
|
||||||
|
const nsIFrame* aChild, const nsRect& aDirty) {
|
||||||
|
if (aChild->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||||
nsIFrame* aChild,
|
nsIFrame* aChild,
|
||||||
|
|
@ -2618,12 +2650,13 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||||
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
|
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
const bool isSVG = child->GetStateBits() & NS_FRAME_SVG_LAYOUT;
|
||||||
|
|
||||||
// true if this is a real or pseudo stacking context
|
// true if this is a real or pseudo stacking context
|
||||||
bool pseudoStackingContext =
|
bool pseudoStackingContext =
|
||||||
(aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
|
(aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
|
||||||
if (!isSVG &&
|
if (!pseudoStackingContext &&
|
||||||
|
!isSVG &&
|
||||||
(aFlags & DISPLAY_CHILD_INLINE) &&
|
(aFlags & DISPLAY_CHILD_INLINE) &&
|
||||||
!child->IsFrameOfType(eLineParticipant)) {
|
!child->IsFrameOfType(eLineParticipant)) {
|
||||||
// child is a non-inline frame in an inline context, i.e.,
|
// child is a non-inline frame in an inline context, i.e.,
|
||||||
|
|
@ -2687,36 +2720,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||||
!aChild->IsSelected()) {
|
!aChild->IsSelected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (aBuilder->GetIncludeAllOutOfFlows() && isPlaceholder) {
|
||||||
if (aBuilder->GetIncludeAllOutOfFlows() &&
|
|
||||||
(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
|
|
||||||
dirty = child->GetVisualOverflowRect();
|
dirty = child->GetVisualOverflowRect();
|
||||||
} else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
|
} else if (!DescendIntoChild(aBuilder, child, dirty)) {
|
||||||
// No need to descend into child to catch placeholders for visible
|
return;
|
||||||
// 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 = PresContext()->PresShell();
|
|
||||||
bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
|
|
||||||
(shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame());
|
|
||||||
if (!keepDescending) {
|
|
||||||
nsRect childDirty;
|
|
||||||
if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 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.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX need to have inline-block and inline-table set pseudoStackingContext
|
// XXX need to have inline-block and inline-table set pseudoStackingContext
|
||||||
|
|
@ -2740,7 +2747,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||||
const nsStyleDisplay* disp = child->StyleDisplay();
|
const nsStyleDisplay* disp = child->StyleDisplay();
|
||||||
const nsStyleEffects* effects = child->StyleEffects();
|
const nsStyleEffects* effects = child->StyleEffects();
|
||||||
const nsStylePosition* pos = child->StylePosition();
|
const nsStylePosition* pos = child->StylePosition();
|
||||||
bool isVisuallyAtomic = child->HasOpacity()
|
const bool isVisuallyAtomic = child->HasOpacity()
|
||||||
|| child->IsTransformed()
|
|| child->IsTransformed()
|
||||||
// strictly speaking, 'perspective' doesn't require visual atomicity,
|
// strictly speaking, 'perspective' doesn't require visual atomicity,
|
||||||
// but the spec says it acts like the rest of these
|
// but the spec says it acts like the rest of these
|
||||||
|
|
@ -2748,23 +2755,22 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||||
|| effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|
|| effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|
||||||
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
|
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
|
||||||
|
|
||||||
bool isPositioned = disp->IsAbsPosContainingBlock(child);
|
const bool isPositioned = disp->IsAbsPosContainingBlock(child);
|
||||||
bool isStackingContext =
|
const bool isStackingContext =
|
||||||
(isPositioned && (disp->IsPositionForcingStackingContext() ||
|
(isPositioned && (disp->IsPositionForcingStackingContext() ||
|
||||||
pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
|
pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
|
||||||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
|
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
|
||||||
disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
|
disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
|
||||||
isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
|
isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
|
||||||
|
|
||||||
if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
|
if (pseudoStackingContext || isStackingContext || isPositioned ||
|
||||||
((effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
|
(!isSVG && disp->IsFloating(child)) ||
|
||||||
IsSVGContentWithCSSClip(child)) ||
|
(isSVG && (effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
|
||||||
disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
|
IsSVGContentWithCSSClip(child))) {
|
||||||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
|
|
||||||
(aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
|
|
||||||
// If you change this, also change IsPseudoStackingContextFromStyle()
|
// If you change this, also change IsPseudoStackingContextFromStyle()
|
||||||
pseudoStackingContext = true;
|
pseudoStackingContext = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ASSERTION(!isStackingContext || pseudoStackingContext,
|
NS_ASSERTION(!isStackingContext || pseudoStackingContext,
|
||||||
"Stacking contexts must also be pseudo-stacking-contexts");
|
"Stacking contexts must also be pseudo-stacking-contexts");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue