From 1ae544f009c6a1e4bd90b33d069c2658f29a6f14 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 19 Feb 2014 16:03:30 -0800 Subject: [PATCH] Bug 63895 (Part 2) - Support table parts as absolute containing blocks. r=dbaron --- layout/base/nsCSSFrameConstructor.cpp | 98 +++++++++++------ layout/base/nsCSSFrameConstructor.h | 12 +-- layout/tables/nsTableCellFrame.cpp | 10 ++ layout/tables/nsTableCellFrame.h | 2 + layout/tables/nsTableFrame.cpp | 139 +++++++++++++++++++++++++ layout/tables/nsTableFrame.h | 30 ++++++ layout/tables/nsTableRowFrame.cpp | 10 ++ layout/tables/nsTableRowFrame.h | 3 + layout/tables/nsTableRowGroupFrame.cpp | 10 ++ layout/tables/nsTableRowGroupFrame.h | 3 + 10 files changed, 281 insertions(+), 36 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index d0cfe7bafb0..05e2d23b005 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -1982,27 +1982,64 @@ nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState, return newFrame; } -nsIFrame* -nsCSSFrameConstructor::ConstructTableRow(nsFrameConstructorState& aState, - FrameConstructionItem& aItem, - nsIFrame* aParentFrame, - const nsStyleDisplay* aDisplay, - nsFrameItems& aFrameItems) +static void +MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState& aState, + const nsStyleDisplay* aDisplay, + nsFrameConstructorSaveState& aAbsSaveState, + nsIFrame* aFrame) { - NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW, + // If we're positioned, then we need to become an absolute containing block + // for any absolutely positioned children and register for post-reflow fixup. + // + // Note that usually if a frame type can be an absolute containing block, we + // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not. + // However, in this case flag serves the additional purpose of indicating that + // the frame was registered with its table frame. This allows us to avoid the + // overhead of unregistering the frame in most cases. + if (aDisplay->IsRelativelyPositionedStyle() || + aDisplay->IsAbsolutelyPositionedStyle() || + aDisplay->HasTransform(aFrame)) { + aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); + aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState); + nsTableFrame::RegisterPositionedTablePart(aFrame); + } +} + +nsIFrame* +nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState, + FrameConstructionItem& aItem, + nsIFrame* aParentFrame, + const nsStyleDisplay* aDisplay, + nsFrameItems& aFrameItems) +{ + NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW || + aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW_GROUP || + aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP || + aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, "Unexpected call"); + MOZ_ASSERT(aItem.mStyleContext->StyleDisplay() == aDisplay, + "Display style doesn't match style context"); nsIContent* const content = aItem.mContent; nsStyleContext* const styleContext = aItem.mStyleContext; const uint32_t nameSpaceID = aItem.mNameSpaceID; nsIFrame* newFrame; - if (kNameSpaceID_MathML == nameSpaceID) - newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext); - else - newFrame = NS_NewTableRowFrame(mPresShell, styleContext); + if (aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW) { + if (kNameSpaceID_MathML == nameSpaceID) + newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext); + else + newFrame = NS_NewTableRowFrame(mPresShell, styleContext); + } else { + newFrame = NS_NewTableRowGroupFrame(mPresShell, styleContext); + } InitAndRestoreFrame(aState, content, aParentFrame, newFrame); + nsFrameConstructorSaveState absoluteSaveState; + MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay, + absoluteSaveState, + newFrame); + nsFrameItems childItems; NS_ASSERTION(aItem.mAnonChildren.IsEmpty(), "nsIAnonymousContentCreator::CreateAnonymousContent " @@ -2105,6 +2142,11 @@ nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState, InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame); + nsFrameConstructorSaveState absoluteSaveState; + MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay, + absoluteSaveState, + newFrame); + nsFrameItems childItems; NS_ASSERTION(aItem.mAnonChildren.IsEmpty(), "nsIAnonymousContentCreator::CreateAnonymousContent " @@ -4375,20 +4417,17 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay, FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), NS_NewTableCaptionFrame) }, { NS_STYLE_DISPLAY_TABLE_ROW_GROUP, - FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW | - FCDATA_SKIP_ABSPOS_PUSH | - FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), - NS_NewTableRowGroupFrame) }, + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, { NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, - FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW | - FCDATA_SKIP_ABSPOS_PUSH | - FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), - NS_NewTableRowGroupFrame) }, + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, { NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP, - FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW | - FCDATA_SKIP_ABSPOS_PUSH | - FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), - NS_NewTableRowGroupFrame) }, + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, { NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP, FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | @@ -4401,7 +4440,7 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay, { NS_STYLE_DISPLAY_TABLE_ROW, FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup), - &nsCSSFrameConstructor::ConstructTableRow) }, + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, { NS_STYLE_DISPLAY_TABLE_CELL, FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow), @@ -8818,15 +8857,14 @@ nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = { FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup), - &nsCSSFrameConstructor::ConstructTableRow), + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup), &nsCSSAnonBoxes::tableRow }, { // Row group - FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | - FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS | - FCDATA_SKIP_ABSPOS_PUSH | - FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), - NS_NewTableRowGroupFrame), + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | + FCDATA_USE_CHILD_ITEMS | + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup), &nsCSSAnonBoxes::tableRowGroup }, { // Column group diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index 771251eb43d..40544161406 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -391,13 +391,13 @@ private: nsFrameItems& aFrameItems); /** - * FrameConstructionData callback used for constructing table rows. + * FrameConstructionData callback for constructing table rows and row groups. */ - nsIFrame* ConstructTableRow(nsFrameConstructorState& aState, - FrameConstructionItem& aItem, - nsIFrame* aParentFrame, - const nsStyleDisplay* aStyleDisplay, - nsFrameItems& aFrameItems); + nsIFrame* ConstructTableRowOrRowGroup(nsFrameConstructorState& aState, + FrameConstructionItem& aItem, + nsIFrame* aParentFrame, + const nsStyleDisplay* aStyleDisplay, + nsFrameItems& aFrameItems); /** * FrameConstructionData callback used for constructing table columns. diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index b3800b55d9c..24314d6c81f 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -87,6 +87,16 @@ nsTableCellFrame::Init(nsIContent* aContent, } } +void +nsTableCellFrame::DestroyFrom(nsIFrame* aDestructRoot) +{ + if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { + nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); + } + + nsContainerFrame::DestroyFrom(aDestructRoot); +} + // nsIPercentHeightObserver methods void diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index dc9cd6d02a7..97ce9f7ecc9 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -47,6 +47,8 @@ public: nsIFrame* aParent, nsIFrame* aPrevInFlow) MOZ_OVERRIDE; + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; + #ifdef ACCESSIBILITY virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; #endif diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 071abc3b25b..044924d9643 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -41,6 +41,7 @@ #include "nsDisplayList.h" #include "nsIScrollableFrame.h" #include "nsCSSProps.h" +#include "RestyleTracker.h" #include using namespace mozilla; @@ -252,6 +253,64 @@ nsTableFrame::PageBreakAfter(nsIFrame* aSourceFrame, return false; } +typedef nsTArray FrameTArray; + +/* static */ void +nsTableFrame::DestroyPositionedTablePartArray(void* aPropertyValue) +{ + auto positionedObjs = static_cast(aPropertyValue); + delete positionedObjs; +} + +/* static */ void +nsTableFrame::RegisterPositionedTablePart(nsIFrame* aFrame) +{ + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(aFrame); + MOZ_ASSERT(tableFrame, "Should have a table frame here"); + tableFrame = static_cast(tableFrame->FirstContinuation()); + + // Retrieve the positioned parts array for this table. + FrameProperties props = tableFrame->Properties(); + auto positionedParts = + static_cast(props.Get(PositionedTablePartArray())); + + // Lazily create the array if it doesn't exist yet. + if (!positionedParts) { + positionedParts = new FrameTArray; + props.Set(PositionedTablePartArray(), positionedParts); + } + + // Add this frame to the list. + positionedParts->AppendElement(aFrame); +} + +/* static */ void +nsTableFrame::UnregisterPositionedTablePart(nsIFrame* aFrame, + nsIFrame* aDestructRoot) +{ + // Retrieve the table frame, and ensure that we hit aDestructRoot on the way. + // If we don't, that means that the table frame will be destroyed, so we don't + // need to bother with unregistering this frame. + nsTableFrame* tableFrame = GetTableFramePassingThrough(aDestructRoot, aFrame); + if (!tableFrame) { + return; + } + tableFrame = static_cast(tableFrame->FirstContinuation()); + + // Retrieve the positioned parts array for this table. + FrameProperties props = tableFrame->Properties(); + auto positionedParts = + static_cast(props.Get(PositionedTablePartArray())); + + // Remove the frame. + MOZ_ASSERT(positionedParts && + positionedParts->IndexOf(aFrame) != FrameTArray::NoIndex, + "Asked to unregister a positioned table part that wasn't registered"); + if (positionedParts) { + positionedParts->RemoveElement(aFrame); + } +} + // XXX this needs to be cleaned up so that the frame constructor breaks out col group // frames into a separate child list, bug 343048. nsresult @@ -1814,6 +1873,10 @@ nsresult nsTableFrame::Reflow(nsPresContext* aPresContext, AdjustForCollapsingRowsCols(aDesiredSize, borderPadding); } + // If there are any relatively-positioned table parts, we need to reflow their + // absolutely-positioned descendants now that their dimensions are final. + FixupPositionedTableParts(aPresContext, aReflowState); + // make sure the table overflow area does include the table rect. nsRect tableRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height()) ; @@ -1834,6 +1897,57 @@ nsresult nsTableFrame::Reflow(nsPresContext* aPresContext, return rv; } +void +nsTableFrame::FixupPositionedTableParts(nsPresContext* aPresContext, + const nsHTMLReflowState& aReflowState) +{ + auto positionedParts = + static_cast(Properties().Get(PositionedTablePartArray())); + if (!positionedParts) { + return; + } + + OverflowChangedTracker overflowTracker; + overflowTracker.SetSubtreeRoot(this); + + for (size_t i = 0; i < positionedParts->Length(); ++i) { + nsIFrame* positionedPart = positionedParts->ElementAt(i); + + // As we've already finished reflow, positionedParts's size and overflow + // areas have already been assigned, so we just pull them back out. + nsSize size(positionedPart->GetSize()); + nsHTMLReflowMetrics desiredSize(aReflowState.GetWritingMode()); + desiredSize.Width() = size.width; + desiredSize.Height() = size.height; + desiredSize.mOverflowAreas = positionedPart->GetOverflowAreasRelativeToSelf(); + + // Construct a dummy reflow state and reflow status. + // XXX(seth): Note that the dummy reflow state doesn't have a correct + // chain of parent reflow states. It also doesn't necessarily have a + // correct containing block. + nsHTMLReflowState reflowState(aPresContext, positionedPart, + aReflowState.rendContext, + nsSize(size.width, NS_UNCONSTRAINEDSIZE), + nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE); + nsReflowStatus reflowStatus = NS_FRAME_COMPLETE; + + // Reflow absolutely-positioned descendants of the positioned part. + // FIXME: Unconditionally using NS_UNCONSTRAINEDSIZE for the height and + // ignoring any change to the reflow status aren't correct. We'll never + // paginate absolutely positioned frames. + overflowTracker.AddFrame(positionedPart); + nsFrame* positionedFrame = static_cast(positionedPart); + positionedFrame->FinishReflowWithAbsoluteFrames(PresContext(), + desiredSize, + reflowState, + reflowStatus, + true); + } + + // Propagate updated overflow areas up the tree. + overflowTracker.Flush(); +} + bool nsTableFrame::UpdateOverflow() { @@ -3444,6 +3558,31 @@ nsTableFrame::GetTableFrame(nsIFrame* aFrame) return nullptr; } +nsTableFrame* +nsTableFrame::GetTableFramePassingThrough(nsIFrame* aMustPassThrough, + nsIFrame* aFrame) +{ + MOZ_ASSERT(aMustPassThrough == aFrame || + nsLayoutUtils::IsProperAncestorFrame(aMustPassThrough, aFrame), + "aMustPassThrough should be an ancestor"); + + // Retrieve the table frame, and ensure that we hit aMustPassThrough on the way. + // If we don't, just return null. + nsTableFrame* tableFrame = nullptr; + for (nsIFrame* ancestor = aFrame; ancestor; ancestor = ancestor->GetParent()) { + if (nsGkAtoms::tableFrame == ancestor->GetType()) { + tableFrame = static_cast(ancestor); + break; + } + if (ancestor == aMustPassThrough) { + return nullptr; + } + } + + MOZ_ASSERT(tableFrame, "Should have a table frame here"); + return tableFrame; +} + bool nsTableFrame::IsAutoHeight() { diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 44646540905..bc2141c65e5 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -111,6 +111,9 @@ class nsTableFrame : public nsContainerFrame public: NS_DECL_FRAMEARENA_HELPERS + static void DestroyPositionedTablePartArray(void* aPropertyValue); + NS_DECLARE_FRAME_PROPERTY(PositionedTablePartArray, DestroyPositionedTablePartArray) + /** nsTableOuterFrame has intimate knowledge of the inner table frame */ friend class nsTableOuterFrame; @@ -146,6 +149,15 @@ public: static bool PageBreakAfter(nsIFrame* aSourceFrame, nsIFrame* aNextFrame); + + // Register a positioned table part with its nsTableFrame. These objects will + // be visited by FixupPositionedTableParts after reflow is complete. (See that + // function for more explanation.) Should be called during frame construction. + static void RegisterPositionedTablePart(nsIFrame* aFrame); + + // Unregister a positioned table part with its nsTableFrame. + static void UnregisterPositionedTablePart(nsIFrame* aFrame, + nsIFrame* aDestructRoot); nsPoint GetFirstSectionOrigin(const nsHTMLReflowState& aReflowState) const; /* @@ -179,6 +191,12 @@ public: /** helper method to find the table parent of any table frame object */ static nsTableFrame* GetTableFrame(nsIFrame* aSourceFrame); + /* Like GetTableFrame, but will return nullptr if we don't pass through + * aMustPassThrough on the way to the table. + */ + static nsTableFrame* GetTableFramePassingThrough(nsIFrame* aMustPassThrough, + nsIFrame* aSourceFrame); + typedef void (* DisplayGenericTablePartTraversal) (nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); @@ -549,6 +567,18 @@ protected: void AdjustForCollapsingRowsCols(nsHTMLReflowMetrics& aDesiredSize, nsMargin aBorderPadding); + /** FixupPositionedTableParts is called at the end of table reflow to reflow + * the absolutely positioned descendants of positioned table parts. This is + * necessary because the dimensions of table parts may change after they've + * been reflowed (e.g. in AdjustForCollapsingRowsCols). + */ + + void FixupPositionedTableParts(nsPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); + + // Clears the list of positioned table parts. + void ClearAllPositionedTableParts(); + nsITableLayoutStrategy* LayoutStrategy() const { return static_cast(FirstInFlow())-> mTableLayoutStrategy; diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 8ac3bf6e0df..1296075078a 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -150,6 +150,16 @@ nsTableRowFrame::Init(nsIContent* aContent, } } +void +nsTableRowFrame::DestroyFrom(nsIFrame* aDestructRoot) +{ + if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { + nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); + } + + nsContainerFrame::DestroyFrom(aDestructRoot); +} + /* virtual */ void nsTableRowFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 99925d6981b..0aedf578ff3 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -36,6 +36,9 @@ public: virtual void Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow) MOZ_OVERRIDE; + + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; + /** @see nsIFrame::DidSetStyleContext */ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE; diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 8b19e9069be..741282ac0c8 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -34,6 +34,16 @@ nsTableRowGroupFrame::~nsTableRowGroupFrame() { } +void +nsTableRowGroupFrame::DestroyFrom(nsIFrame* aDestructRoot) +{ + if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { + nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); + } + + nsContainerFrame::DestroyFrom(aDestructRoot); +} + NS_QUERYFRAME_HEAD(nsTableRowGroupFrame) NS_QUERYFRAME_ENTRY(nsTableRowGroupFrame) NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index ff466333743..98f27b47afb 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -67,6 +67,9 @@ public: */ friend nsIFrame* NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); virtual ~nsTableRowGroupFrame(); + + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; + /** @see nsIFrame::DidSetStyleContext */ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE;