summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/nsFrame.cpp')
-rw-r--r--layout/generic/nsFrame.cpp204
1 files changed, 122 insertions, 82 deletions
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 024cc39bd..1c31f517d 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1793,6 +1793,13 @@ void
nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
+ // Per https://drafts.csswg.org/css-tables-3/#global-style-overrides:
+ // "All css properties of table-column and table-column-group boxes are
+ // ignored, except when explicitly specified by this specification."
+ // CSS outlines fall into this category, so we skip them on these boxes.
+
+ MOZ_ASSERT(GetType() != nsGkAtoms::tableColGroupFrame && GetType() != nsGkAtoms::tableColFrame);
+
if (StyleOutline()->mOutlineStyle == NS_STYLE_BORDER_STYLE_NONE) {
return;
}
@@ -1813,7 +1820,7 @@ nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
void
nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
- const nsRect& aDirtyRect, nsDisplayList* aList)
+ nsDisplayList* aList)
{
if (!IsVisibleForPainting(aBuilder))
return;
@@ -1839,7 +1846,9 @@ nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
if (aBuilder->IsForEventDelivery() || aForceBackground ||
!StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) {
return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
- aBuilder, this, GetRectRelativeToSelf(), aLists.BorderBackground());
+ aBuilder, this,
+ GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this),
+ aLists.BorderBackground());
}
return false;
}
@@ -1872,7 +1881,9 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
// If there's a themed background, we should not create a border item.
// It won't be rendered.
- if (!bgIsThemed && StyleBorder()->HasBorder()) {
+ // Don't paint borders for tables here, since they paint them in a different
+ // order.
+ if (!bgIsThemed && StyleBorder()->HasBorder() && GetType() != nsGkAtoms::tableFrame) {
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayBorder(aBuilder, this));
}
@@ -2072,13 +2083,12 @@ ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem)
static void
WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsRect& aDirtyRect,
nsDisplayList* aSource, nsDisplayList* aTarget,
int aIndex) {
if (!aSource->IsEmpty()) {
nsDisplayTransform *sepIdItem =
new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aSource,
- aDirtyRect, Matrix4x4(), aIndex);
+ aBuilder->GetDirtyRect(), Matrix4x4(), aIndex);
sepIdItem->SetNoExtendContext();
aTarget->AppendToTop(sepIdItem);
}
@@ -2086,7 +2096,6 @@ WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
void
nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
- const nsRect& aDirtyRect,
nsDisplayList* aList) {
if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return;
@@ -2122,25 +2131,27 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
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;
- if (extend3DContext && !Combines3DTransformWithAncestors()) {
+ if (extend3DContext && !combines3DTransformWithAncestors) {
// Start a new preserves3d context to keep informations on
// nsDisplayListBuilder.
autoPreserves3DContext.emplace(aBuilder);
// Save dirty rect on the builder to avoid being distorted for
// multiple transforms along the chain.
- aBuilder->SetPreserves3DDirtyRect(aDirtyRect);
+ aBuilder->SavePreserves3DRects();
}
// For preserves3d, use the dirty rect already installed on the
// builder, since aDirtyRect maybe distorted for transforms along
// the chain.
- nsRect dirtyRect = aDirtyRect;
+ 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
// a nsDisplayBlendContainer. Set the blend mode back when the routine exits
// so we keep track if the parent stacking context needs a container too.
@@ -2148,6 +2159,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
aBuilder->SetContainsBlendMode(false);
nsRect dirtyRectOutsideTransform = dirtyRect;
+ bool inTransform = aBuilder->IsInTransform();
if (isTransformed) {
const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder,
@@ -2160,8 +2172,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// If we're in preserve-3d then grab the dirty rect that was given to the root
// and transform using the combined transform.
- if (Combines3DTransformWithAncestors()) {
- dirtyRect = aBuilder->GetPreserves3DDirtyRect(this);
+ if (combines3DTransformWithAncestors) {
+ dirtyRect = aBuilder->GetPreserves3DRects();
}
nsRect untransformedDirtyRect;
@@ -2269,19 +2281,19 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
clipState.EnterStackingContextContents(clearClip);
- nsDisplayListCollection set;
+ nsDisplayListCollection set(aBuilder);
{
DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
nsDisplayListBuilder::AutoInTransformSetter
inTransformSetter(aBuilder, inTransform);
nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
- perspectiveIndex(aBuilder, this);
+ perspectiveIndex(aBuilder, childrenHavePerspective);
CheckForApzAwareEventHandlers(aBuilder, this);
Maybe<nsRect> clipPropClip = GetClipPropClipRect(disp, effects, GetSize());
if (clipPropClip) {
- dirtyRect.IntersectRect(dirtyRect, *clipPropClip);
+ aBuilder->IntersectDirtyRect(*clipPropClip);
nestedClipState.ClipContentDescendants(
*clipPropClip + aBuilder->ToReferenceFrame(this));
}
@@ -2294,7 +2306,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
aBuilder->MarkPreserve3DFramesForDisplayList(this);
}
- MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
+ MarkAbsoluteFramesForDisplayList(aBuilder);
nsDisplayLayerEventRegions* eventRegions = nullptr;
if (aBuilder->IsBuildingLayerEventRegions()) {
@@ -2303,7 +2315,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
aBuilder->SetLayerEventRegions(eventRegions);
}
aBuilder->AdjustWindowDraggingRegion(this);
- BuildDisplayList(aBuilder, dirtyRect, set);
+ BuildDisplayList(aBuilder, set);
if (eventRegions) {
// If the event regions item ended up empty, throw it away rather than
// adding it to the display list.
@@ -2409,7 +2421,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
// Revert to the post-filter dirty rect.
- buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
+ aBuilder->SetDirtyRect(dirtyRectOutsideSVGEffects);
// Skip all filter effects while generating glyph mask.
if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
@@ -2474,8 +2486,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
while (nsDisplayItem* item = resultList.RemoveBottom()) {
if (ItemParticipatesIn3DContext(this, item) && !item->GetClip().HasClip()) {
// The frame of this item participates the same 3D context.
- WrapSeparatorTransform(aBuilder, this, dirtyRect,
- &nonparticipants, &participants, index++);
+ WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
participants.AppendToTop(item);
} else {
// The frame of the item doesn't participate the current
@@ -2488,8 +2499,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nonparticipants.AppendToTop(item);
}
}
- WrapSeparatorTransform(aBuilder, this, dirtyRect,
- &nonparticipants, &participants, index++);
+ WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
resultList.AppendToTop(&participants);
}
@@ -2500,7 +2510,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
}
// Revert to the dirtyrect coming in from the parent, without our transform
// taken into account.
- buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform);
+ aBuilder->SetDirtyRect(dirtyRectOutsideTransform);
// Revert to the outer reference frame and offset because all display
// items we create from now on are outside the transform.
nsPoint toOuterReferenceFrame;
@@ -2601,10 +2611,63 @@ WrapInWrapList(nsDisplayListBuilder* aBuilder,
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;
+ }
+
+ if (aChild->IsFrameOfType(nsIFrame::eTablePart)) {
+ // Relative positioning and transforms can cause table parts to move, but we
+ // will still paint the backgrounds for their ancestor parts under them at
+ // their 'normal' position. That means that we must consider the overflow
+ // rects at both positions.
+
+ // We convert the overflow rect into the nsTableFrame's coordinate
+ // space, applying the normal position offset at each step. Then we
+ // compare that against the builder's cached dirty rect in table
+ // coordinate space.
+ const nsIFrame* f = aChild;
+ nsRect normalPositionOverflowRelativeToTable = overflow;
+
+ while (f->IsFrameOfType(nsIFrame::eTablePart)) {
+ normalPositionOverflowRelativeToTable += f->GetNormalPosition();
+ f = f->GetParent();
+ }
+
+ nsDisplayTableBackgroundSet* tableBGs = aBuilder->GetTableBackgroundSet();
+ if (tableBGs &&
+ tableBGs->GetDirtyRect().Intersects(normalPositionOverflowRelativeToTable)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void
nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
nsIFrame* aChild,
- const nsRect& aDirtyRect,
const nsDisplayListSet& aLists,
uint32_t aFlags) {
// If painting is restricted to just the background of the top level frame,
@@ -2623,12 +2686,13 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
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
bool pseudoStackingContext =
(aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
- if (!isSVG &&
+ if (!pseudoStackingContext &&
+ !isSVG &&
(aFlags & DISPLAY_CHILD_INLINE) &&
!child->IsFrameOfType(eLineParticipant)) {
// child is a non-inline frame in an inline context, i.e.,
@@ -2637,12 +2701,14 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
pseudoStackingContext = true;
}
- // dirty rect in child-relative coordinates
- nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
-
nsIAtom* childType = child->GetType();
nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
bool isPlaceholder = false;
+
+ // dirty rect in child-relative coordinates
+ NS_ASSERTION(aBuilder->GetCurrentFrame() == this, "Wrong coord space!");
+ nsRect dirty = aBuilder->GetDirtyRect() - child->GetOffsetTo(this);
+
if (childType == nsGkAtoms::placeholderFrame) {
isPlaceholder = true;
nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
@@ -2689,35 +2755,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
!aChild->IsSelected()) {
return;
}
-
- if (aBuilder->GetIncludeAllOutOfFlows() &&
- (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+ if (aBuilder->GetIncludeAllOutOfFlows() && isPlaceholder) {
dirty = child->GetVisualOverflowRect();
- } else 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 = 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.
- }
+ } else if (!DescendIntoChild(aBuilder, child, dirty)) {
+ return;
}
// XXX need to have inline-block and inline-table set pseudoStackingContext
@@ -2741,7 +2782,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* disp = child->StyleDisplay();
const nsStyleEffects* effects = child->StyleEffects();
const nsStylePosition* pos = child->StylePosition();
- bool isVisuallyAtomic = child->HasOpacity()
+ const bool isVisuallyAtomic = child->HasOpacity()
|| child->IsTransformed()
// strictly speaking, 'perspective' doesn't require visual atomicity,
// but the spec says it acts like the rest of these
@@ -2749,28 +2790,28 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|| effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
- bool isPositioned = disp->IsAbsPosContainingBlock(child);
- bool isStackingContext =
+ const bool isPositioned = disp->IsAbsPosContainingBlock(child);
+ const bool isStackingContext =
(isPositioned && (disp->IsPositionForcingStackingContext() ||
pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
- if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
- ((effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
- IsSVGContentWithCSSClip(child)) ||
- disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
- (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
- (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
+ if (pseudoStackingContext || isStackingContext || isPositioned ||
+ (!isSVG && disp->IsFloating(child)) ||
+ (isSVG && (effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
+ IsSVGContentWithCSSClip(child))) {
// If you change this, also change IsPseudoStackingContextFromStyle()
pseudoStackingContext = true;
}
+
NS_ASSERTION(!isStackingContext || pseudoStackingContext,
"Stacking contexts must also be pseudo-stacking-contexts");
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, child, dirty, pseudoStackingContext);
+
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
CheckForApzAwareEventHandlers(aBuilder, child);
@@ -2783,7 +2824,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
savedOutOfFlowData->mContainingBlockScrollClip);
} else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
isPlaceholder) {
- NS_ASSERTION(dirty.IsEmpty(), "should have empty dirty rect");
+ NS_ASSERTION(dirty.IsEmpty(), "should have empty visible rect");
// Every item we build from now until we descent into an out of flow that
// does have saved out of flow data should be invisible. This state gets
// restored when AutoBuildingDisplayList gets out of scope.
@@ -2819,18 +2860,18 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// True stacking context.
// For stacking contexts, BuildDisplayListForStackingContext handles
// clipping and MarkAbsoluteFramesForDisplayList.
- child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
- aBuilder->DisplayCaret(child, dirty, &list);
+ child->BuildDisplayListForStackingContext(aBuilder, &list);
+ aBuilder->DisplayCaret(child, &list);
} else {
Maybe<nsRect> clipPropClip =
child->GetClipPropClipRect(disp, effects, child->GetSize());
if (clipPropClip) {
- dirty.IntersectRect(dirty, *clipPropClip);
+ aBuilder->IntersectDirtyRect(*clipPropClip);
clipState.ClipContentDescendants(
*clipPropClip + aBuilder->ToReferenceFrame(child));
}
- child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
+ child->MarkAbsoluteFramesForDisplayList(aBuilder);
if (aBuilder->IsBuildingLayerEventRegions()) {
// If this frame has a different animated geometry root than its parent,
@@ -2862,8 +2903,8 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// return early.
aBuilder->AdjustWindowDraggingRegion(child);
- child->BuildDisplayList(aBuilder, dirty, aLists);
- aBuilder->DisplayCaret(child, dirty, aLists.Content());
+ child->BuildDisplayList(aBuilder, aLists);
+ aBuilder->DisplayCaret(child, aLists.Content());
#ifdef DEBUG
DisplayDebugBorders(aBuilder, child, aLists);
#endif
@@ -2874,10 +2915,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// We allow positioned descendants of the child to escape to our parent
// stacking context's positioned descendant list, because they might be
// z-index:non-auto
- nsDisplayListCollection pseudoStack;
+ nsDisplayListCollection pseudoStack(aBuilder);
aBuilder->AdjustWindowDraggingRegion(child);
- child->BuildDisplayList(aBuilder, dirty, pseudoStack);
- aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
+ child->BuildDisplayList(aBuilder, pseudoStack);
+ aBuilder->DisplayCaret(child, pseudoStack.Content());
list.AppendToTop(pseudoStack.BorderBackground());
list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
@@ -2927,11 +2968,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
}
void
-nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
- const nsRect& aDirtyRect)
+nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder)
{
if (IsAbsoluteContainer()) {
- aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect);
+ aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList());
}
}