Bug 1024454 - Part 1: Eagerly propagate dirty bits so absolute children of table parts get reflowed reliably. r=dbaron, a=lmandel
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4324,16 +4324,28 @@ nsFrame::ReflowAbsoluteFrames(nsPresCont
nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
containingBlock,
aConstrainHeight, true, true, // XXX could be optimized
&aDesiredSize.mOverflowAreas);
}
}
+void
+nsFrame::PushDirtyBitToAbsoluteFrames()
+{
+ if (!(GetStateBits() & NS_FRAME_IS_DIRTY)) {
+ return; // No dirty bit to push.
+ }
+ if (!HasAbsolutelyPositionedChildren()) {
+ return; // No absolute children to push to.
+ }
+ GetAbsoluteContainingBlock()->MarkAllFramesDirty();
+}
+
/* virtual */ bool
nsFrame::CanContinueTextRun() const
{
// By default, a frame will *not* allow a text run to be continued
// through it.
return false;
}
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -326,16 +326,30 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
bool aConstrainHeight = true);
void FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
bool aConstrainHeight = true);
+
+ /*
+ * If this frame is dirty, marks all absolutely-positioned children of this
+ * frame dirty. If this frame isn't dirty, or if there are no
+ * absolutely-positioned children, does nothing.
+ *
+ * It's necessary to use PushDirtyBitToAbsoluteFrames() when you plan to
+ * reflow this frame's absolutely-positioned children after the dirty bit on
+ * this frame has already been cleared, which prevents nsHTMLReflowState from
+ * propagating the dirty bit normally. This situation generally only arises
+ * when a multipass layout algorithm is used.
+ */
+ void PushDirtyBitToAbsoluteFrames();
+
virtual bool CanContinueTextRun() const MOZ_OVERRIDE;
virtual bool UpdateOverflow() MOZ_OVERRIDE;
// Selection Methods
NS_IMETHOD HandlePress(nsPresContext* aPresContext,
mozilla::WidgetGUIEvent* aEvent,
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -1008,16 +1008,21 @@ nsTableCellFrame::Reflow(nsPresContext*
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
InvalidateFrame();
}
// remember the desired size for this reflow
SetDesiredSize(aDesiredSize);
+ // Any absolutely-positioned children will get reflowed in
+ // nsFrame::FixupPositionedTableParts in another pass, so propagate our
+ // dirtiness to them before our parent clears our dirty bits.
+ PushDirtyBitToAbsoluteFrames();
+
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
/* ----- global methods ----- */
NS_QUERYFRAME_HEAD(nsTableCellFrame)
NS_QUERYFRAME_ENTRY(nsTableCellFrame)
NS_QUERYFRAME_ENTRY(nsITableCellLayout)
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -1052,16 +1052,21 @@ nsTableRowFrame::Reflow(nsPresContext*
// If our parent is in initial reflow, it'll handle invalidating our
// entire overflow rect.
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
InvalidateFrame();
}
+ // Any absolutely-positioned children will get reflowed in
+ // nsFrame::FixupPositionedTableParts in another pass, so propagate our
+ // dirtiness to them before our parent clears our dirty bits.
+ PushDirtyBitToAbsoluteFrames();
+
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
/**
* This function is called by the row group frame's SplitRowGroup() code when
* pushing a row frame that has cell frames that span into it. The cell frame
* should be reflowed with the specified height
*/
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -1347,16 +1347,22 @@ nsTableRowGroupFrame::Reflow(nsPresConte
// If our parent is in initial reflow, it'll handle invalidating our
// entire overflow rect.
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
InvalidateFrame();
}
FinishAndStoreOverflow(&aDesiredSize);
+
+ // Any absolutely-positioned children will get reflowed in
+ // nsFrame::FixupPositionedTableParts in another pass, so propagate our
+ // dirtiness to them before our parent clears our dirty bits.
+ PushDirtyBitToAbsoluteFrames();
+
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
bool
nsTableRowGroupFrame::UpdateOverflow()
{
// Row cursor invariants depend on the visual overflow area of the rows,
// which may have changed, so we need to clear the cursor now.