diff --git a/mozilla/layout/base/nsDisplayList.cpp b/mozilla/layout/base/nsDisplayList.cpp index 6003a476289..9966bb683dc 100644 --- a/mozilla/layout/base/nsDisplayList.cpp +++ b/mozilla/layout/base/nsDisplayList.cpp @@ -56,6 +56,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, : mReferenceFrame(aReferenceFrame), mMovingFrame(aMovingFrame), mIgnoreScrollFrame(nsnull), + mCurrentTableItem(nsnull), mBuildCaret(aBuildCaret), mEventDelivery(aIsForEvents), mIsAtRootOfPseudoStackingContext(PR_FALSE), @@ -136,6 +137,7 @@ nsDisplayListBuilder::~nsDisplayListBuilder() { "All frames should have been unmarked"); NS_ASSERTION(mPresShellStates.Length() == 0, "All presshells should have been exited"); + NS_ASSERTION(!mCurrentTableItem, "No table item should be active"); PL_FreeArenaPool(&mPool); PL_FinishArenaPool(&mPool); @@ -525,11 +527,8 @@ nsDisplayBackground::IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder, // will move relative to its viewport, which means this display item will // change when it is moved. If they are in different documents, we do not // want to return true because mFrame won't move relative to its viewport. - for (nsIFrame* f = mFrame; f; f = f->GetParent()) { - if (f == aAncestorFrame) - return PR_TRUE; - } - return PR_FALSE; + return mFrame == aAncestorFrame || + nsLayoutUtils::IsProperAncestorFrame(aAncestorFrame, mFrame); } void diff --git a/mozilla/layout/base/nsDisplayList.h b/mozilla/layout/base/nsDisplayList.h index 5f3a100cdc6..cb70187ade6 100644 --- a/mozilla/layout/base/nsDisplayList.h +++ b/mozilla/layout/base/nsDisplayList.h @@ -62,6 +62,7 @@ class nsIContent; class nsRegion; class nsIRenderingContext; class nsIDeviceContext; +class nsDisplayTableItem; /* * An nsIFrame can have many different visual parts. For example an image frame @@ -281,6 +282,10 @@ public: PRPackedBool mOldValue; }; + // Helpers for tables + nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; } + void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; } + private: // This class is only used on stack, so we don't have to worry about leaking // it. Don't let us be heap-allocated! @@ -304,6 +309,7 @@ private: nsCOMPtr mBoundingSelection; nsAutoTArray mPresShellStates; nsAutoTArray mFramesMarkedForDisplay; + nsDisplayTableItem* mCurrentTableItem; PRPackedBool mBuildCaret; PRPackedBool mEventDelivery; PRPackedBool mIsBackgroundOnly; diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index d870cfa5ced..fce69581529 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -362,9 +362,9 @@ nsTableCellFrame::PaintCellBackground(nsIRenderingContext& aRenderingContext, PaintBackground(aRenderingContext, aDirtyRect, aPt); } -class nsDisplayTableCellBackground : public nsDisplayItem { +class nsDisplayTableCellBackground : public nsDisplayTableItem { public: - nsDisplayTableCellBackground(nsTableCellFrame* aFrame) : nsDisplayItem(aFrame) { + nsDisplayTableCellBackground(nsTableCellFrame* aFrame) : nsDisplayTableItem(aFrame) { MOZ_COUNT_CTOR(nsDisplayTableCellBackground); } #ifdef NS_BUILD_REFCNT_LOGGING @@ -377,6 +377,8 @@ public: HitTestState* aState) { return mFrame; } virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, const nsRect& aDirtyRect); + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); + NS_DISPLAY_DECL_NAME("TableCellBackground") }; @@ -387,6 +389,14 @@ void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder, PaintBackground(*aCtx, aDirtyRect, aBuilder->ToReferenceFrame(mFrame)); } +nsRect +nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder) +{ + // revert from nsDisplayTableItem's implementation ... cell backgrounds + // don't overflow the cell + return nsDisplayItem::GetBounds(aBuilder); +} + static void PaintTableCellSelection(nsIFrame* aFrame, nsIRenderingContext* aCtx, const nsRect& aRect, nsPoint aPt) @@ -411,16 +421,24 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); + if (!isRoot) { + nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); + NS_ASSERTION(currentItem, "No current table item???"); + currentItem->UpdateForFrameBackground(this); + } + // display background if we need to. if (aBuilder->IsForEventDelivery() || - (((!tableFrame->IsBorderCollapse() || aBuilder->IsAtRootOfPseudoStackingContext()) && + (((!tableFrame->IsBorderCollapse() || isRoot) && (!GetStyleBackground()->IsTransparent() || GetStyleDisplay()->mAppearance)))) { // The cell background was not painted by the nsTablePainter, // so we need to do it. We have special background processing here // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline - nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayTableCellBackground(this)); + nsDisplayTableItem* item = new (aBuilder) nsDisplayTableCellBackground(this); + nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); + item->UpdateForFrameBackground(this); } // display borders if we need to diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 0029499d87f..3c5c2b0b0b5 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -1256,9 +1256,46 @@ nsTableFrame::GetAdditionalChildListName(PRInt32 aIndex) const return nsnull; } -class nsDisplayTableBorderBackground : public nsDisplayItem { +nsRect +nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder) { + return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame); +} + +PRBool +nsDisplayTableItem::IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aAncestorFrame) +{ + if (!mPartHasFixedBackground) + return PR_FALSE; + + // aAncestorFrame is the frame that is going to be moved. + // Check if mFrame is equal to aAncestorFrame or aAncestorFrame is an + // ancestor of mFrame in the same document. If this is true, mFrame + // will move relative to its viewport, which means this display item will + // change when it is moved. If they are in different documents, we do not + // want to return true because mFrame won't move relative to its viewport. + return mFrame == aAncestorFrame || + nsLayoutUtils::IsProperAncestorFrame(aAncestorFrame, mFrame); +} + +/* static */ void +nsDisplayTableItem::UpdateForFrameBackground(nsIFrame* aFrame) +{ + PRBool isCanvas; + const nsStyleBackground* bg; + PRBool hasBG = + nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bg, &isCanvas); + if (!hasBG) + return; + if (!bg->HasFixedBackground()) + return; + + mPartHasFixedBackground = PR_TRUE; +} + +class nsDisplayTableBorderBackground : public nsDisplayTableItem { public: - nsDisplayTableBorderBackground(nsTableFrame* aFrame) : nsDisplayItem(aFrame) { + nsDisplayTableBorderBackground(nsTableFrame* aFrame) : nsDisplayTableItem(aFrame) { MOZ_COUNT_CTOR(nsDisplayTableBorderBackground); } #ifdef NS_BUILD_REFCNT_LOGGING @@ -1269,13 +1306,6 @@ public: virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, const nsRect& aDirtyRect); - // With collapsed borders, parts of the collapsed border can extend outside - // the table frame, so allow this display element to blow out to our - // overflow rect. - virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return static_cast(mFrame)->GetOverflowRect() + - aBuilder->ToReferenceFrame(mFrame); - } NS_DISPLAY_DECL_NAME("TableBorderBackground") }; @@ -1332,16 +1362,24 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, - PRBool aIsRoot, + nsDisplayTableItem* aDisplayItem, DisplayGenericTablePartTraversal aTraversal) { nsDisplayList eventsBorderBackground; // If we need to sort the event backgrounds, then we'll put descendants' // display items into their own set of lists. - PRBool sortEventBackgrounds = aIsRoot && aBuilder->IsForEventDelivery(); + PRBool sortEventBackgrounds = aDisplayItem && aBuilder->IsForEventDelivery(); nsDisplayListCollection separatedCollection; const nsDisplayListSet* lists = sortEventBackgrounds ? &separatedCollection : &aLists; + nsAutoPushCurrentTableItem pushTableItem; + if (aDisplayItem) { + pushTableItem.Push(aBuilder, aDisplayItem); + } + nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); + NS_ASSERTION(currentItem, "No current table item!"); + currentItem->UpdateForFrameBackground(aFrame); + // Create dedicated background display items per-frame when we're // handling events. // XXX how to handle collapsed borders? @@ -1381,11 +1419,11 @@ nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // This background is created regardless of whether this frame is // visible or not. Visibility decisions are delegated to the // table background painter. - nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayTableBorderBackground(this)); + nsDisplayTableItem* item = new (aBuilder) nsDisplayTableBorderBackground(this); + nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); - return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, PR_TRUE); + return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); } // XXX We don't put the borders and backgrounds in tree order like we should. diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index e9de1e75afe..4de68e5735c 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -47,6 +47,7 @@ #include "nsTableColGroupFrame.h" #include "nsCellMap.h" #include "nsGkAtoms.h" +#include "nsDisplayList.h" class nsTableCellFrame; class nsTableColFrame; @@ -72,6 +73,58 @@ static inline PRBool IS_TABLE_CELL(nsIAtom* frameType) { nsGkAtoms::bcTableCellFrame == frameType; } +class nsDisplayTableItem : public nsDisplayItem +{ +public: + nsDisplayTableItem(nsIFrame* aFrame) : nsDisplayItem(aFrame), + mPartHasFixedBackground(PR_FALSE) {} + + virtual PRBool IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aAncestorFrame); + // With collapsed borders, parts of the collapsed border can extend outside + // the table part frames, so allow this display element to blow out to our + // overflow rect. This is also useful for row frames that have spanning + // cells extending outside them. + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); + + void UpdateForFrameBackground(nsIFrame* aFrame); + +private: + PRPackedBool mPartHasFixedBackground; +}; + +class nsAutoPushCurrentTableItem +{ +public: + nsAutoPushCurrentTableItem() : mBuilder(nsnull) {} + + void Push(nsDisplayListBuilder* aBuilder, nsDisplayTableItem* aPushItem) + { + mBuilder = aBuilder; + mOldCurrentItem = aBuilder->GetCurrentTableItem(); + aBuilder->SetCurrentTableItem(aPushItem); +#ifdef DEBUG + mPushedItem = aPushItem; +#endif + } + ~nsAutoPushCurrentTableItem() { + if (!mBuilder) + return; +#ifdef DEBUG + NS_ASSERTION(mBuilder->GetCurrentTableItem() == mPushedItem, + "Someone messed with the current table item behind our back!"); +#endif + mBuilder->SetCurrentTableItem(mOldCurrentItem); + } + +private: + nsDisplayListBuilder* mBuilder; + nsDisplayTableItem* mOldCurrentItem; +#ifdef DEBUG + nsDisplayTableItem* mPushedItem; +#endif +}; + /* ============================================================================ */ /** nsTableFrame maps the inner portion of a table (everything except captions.) @@ -176,8 +229,8 @@ public: * and row frames. It creates a background display item for handling events * if necessary, an outline display item if necessary, and displays * all the the frame's children. - * @param aIsRoot true if aFrame is the table frame or a table part which - * happens to be the root of a stacking context + * @param aDisplayItem the display item created for this part, or null + * if this part's border/background painting is delegated to an ancestor * @param aTraversal a function that gets called to traverse the table * part's child frames and add their display list items to a * display list set. @@ -186,7 +239,7 @@ public: nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, - PRBool aIsRoot, + nsDisplayTableItem* aDisplayItem, DisplayGenericTablePartTraversal aTraversal = GenericTraversal); // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 173000dad5c..76c4835a578 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -545,9 +545,9 @@ nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState) * Table row backgrounds can extend beyond the row frame bounds, when * the row contains row-spanning cells. */ -class nsDisplayTableRowBackground : public nsDisplayItem { +class nsDisplayTableRowBackground : public nsDisplayTableItem { public: - nsDisplayTableRowBackground(nsTableRowFrame* aFrame) : nsDisplayItem(aFrame) { + nsDisplayTableRowBackground(nsTableRowFrame* aFrame) : nsDisplayTableItem(aFrame) { MOZ_COUNT_CTOR(nsDisplayTableRowBackground); } #ifdef NS_BUILD_REFCNT_LOGGING @@ -556,13 +556,6 @@ public: } #endif - virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - // the overflow rect contains any row-spanning cells, so it contains - // our background. Note that this means we may not be opaque even if - // the background style is a solid color. - return static_cast(mFrame)->GetOverflowRect() + - aBuilder->ToReferenceFrame(mFrame); - } virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, const nsRect& aDirtyRect); NS_DISPLAY_DECL_NAME("TableRowBackground") @@ -590,6 +583,7 @@ nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return NS_OK; PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); + nsDisplayTableItem* item = nsnull; if (isRoot) { // This background is created regardless of whether this frame is // visible or not. Visibility decisions are delegated to the @@ -597,12 +591,12 @@ nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // We would use nsDisplayGeneric for this rare case except that we // need the background to be larger than the row frame in some // cases. - nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayTableRowBackground(this)); + item = new (aBuilder) nsDisplayTableRowBackground(this); + nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); } - return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, isRoot); + return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); } PRIntn diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index b2ea5e3782c..2a55c2deeff 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -187,17 +187,40 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsPresContext* aPresContext, return NS_OK; } -static void -PaintRowGroupBackground(nsIFrame* aFrame, nsIRenderingContext* aCtx, - const nsRect& aDirtyRect, nsPoint aPt) -{ - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(aFrame); +/** + * We need a custom display item for table row backgrounds. This is only used + * when the table row is the root of a stacking context (e.g., has 'opacity'). + * Table row backgrounds can extend beyond the row frame bounds, when + * the row contains row-spanning cells. + */ +class nsDisplayTableRowGroupBackground : public nsDisplayTableItem { +public: + nsDisplayTableRowGroupBackground(nsTableRowGroupFrame* aFrame) : nsDisplayTableItem(aFrame) { + MOZ_COUNT_CTOR(nsDisplayTableRowGroupBackground); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayTableRowGroupBackground() { + MOZ_COUNT_DTOR(nsDisplayTableRowGroupBackground); + } +#endif + virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, + const nsRect& aDirtyRect); + + NS_DISPLAY_DECL_NAME("TableRowGroupBackground") +}; + +void +nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder* aBuilder, + nsIRenderingContext* aCtx, const nsRect& aDirtyRect) { + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame); + + nsPoint pt = aBuilder->ToReferenceFrame(mFrame); TableBackgroundPainter painter(tableFrame, TableBackgroundPainter::eOrigin_TableRowGroup, - aFrame->PresContext(), *aCtx, - aDirtyRect, aPt); - painter.PaintRowGroup(static_cast(aFrame)); + mFrame->PresContext(), *aCtx, + aDirtyRect, pt); + painter.PaintRowGroup(static_cast(mFrame)); } // Handle the child-traversal part of DisplayGenericTablePart @@ -261,17 +284,18 @@ nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return NS_OK; PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); + nsDisplayTableItem* item = nsnull; if (isRoot) { // This background is created regardless of whether this frame is // visible or not. Visibility decisions are delegated to the // table background painter. - nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayGeneric(this, PaintRowGroupBackground, "TableRowGroupBackground")); + item = new (aBuilder) nsDisplayTableRowGroupBackground(this); + nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); } return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, - aLists, isRoot, DisplayRows); + aLists, item, DisplayRows); } PRIntn