diff options
29 files changed, 488 insertions, 340 deletions
diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index a869564a4f..55461f7c0a 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -721,7 +721,6 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, : mReferenceFrame(aReferenceFrame), mIgnoreScrollFrame(nullptr), mLayerEventRegions(nullptr), - mCurrentTableItem(nullptr), mCurrentFrame(aReferenceFrame), mCurrentReferenceFrame(aReferenceFrame), mCurrentAGR(&mRootAGR), @@ -731,6 +730,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mGlassDisplayItem(nullptr), mScrollInfoItemsForHoisting(nullptr), mMode(aMode), + mTableBackgroundSet(nullptr), mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID), mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID), mCurrentScrollbarFlags(0), @@ -926,7 +926,6 @@ 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"); nsCSSRendering::EndFrameTreesLocked(); @@ -2579,8 +2578,7 @@ static nsStyleContext* GetBackgroundStyleContext(nsIFrame* aFrame) /* static */ void SetBackgroundClipRegion(DisplayListClipState::AutoSaveRestore& aClipState, - nsIFrame* aFrame, const nsPoint& aToReferenceFrame, - const nsStyleImageLayers::Layer& aLayer, + nsIFrame* aFrame, const nsStyleImageLayers::Layer& aLayer, const nsRect& aBackgroundRect, bool aWillPaintBorder) { @@ -2640,14 +2638,16 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil bool aAllowWillPaintBorderOptimization, nsStyleContext* aStyleContext, const nsRect& aBackgroundOriginRect, - nsIFrame* aSecondaryReferenceFrame) + nsIFrame* aSecondaryReferenceFrame, + Maybe<nsDisplayListBuilder::AutoBuildingDisplayList>* + aAutoBuildingDisplayList) { nsStyleContext* bgSC = aStyleContext; const nsStyleBackground* bg = nullptr; - nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame); + nsRect bgRect = aBackgroundRect; nsRect bgOriginRect = bgRect; if (!aBackgroundOriginRect.IsEmpty()) { - bgOriginRect = aBackgroundOriginRect + aBuilder->ToReferenceFrame(aFrame); + bgOriginRect = aBackgroundOriginRect; } nsPresContext* presContext = aFrame->PresContext(); bool isThemed = aFrame->IsThemed(); @@ -2683,8 +2683,6 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil !isThemed && !hasInsetShadow && borderStyle->HasBorder(); - nsPoint toRef = aBuilder->ToReferenceFrame(aFrame); - // An auxiliary list is necessary in case we have background blending; if that // is the case, background items need to be wrapped by a blend container to // isolate blending to the background @@ -2693,6 +2691,9 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil // to create an item for hit testing. if ((drawBackgroundColor && color != NS_RGBA(0,0,0,0)) || aBuilder->IsForEventDelivery()) { + if (aAutoBuildingDisplayList && !*aAutoBuildingDisplayList) { + aAutoBuildingDisplayList->emplace(aBuilder, aFrame); + } DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (bg && !aBuilder->IsForEventDelivery()) { // Disable the will-paint-border optimization for background @@ -2704,7 +2705,7 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil // artifacts along the rounded corners. bool useWillPaintBorderOptimization = willPaintBorder && nsLayoutUtils::HasNonZeroCorner(borderStyle->mBorderRadius); - SetBackgroundClipRegion(clipState, aFrame, toRef, + SetBackgroundClipRegion(clipState, aFrame, bg->BottomLayer(), bgRect, useWillPaintBorderOptimization); } @@ -2757,6 +2758,10 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil continue; } + if (aAutoBuildingDisplayList && !*aAutoBuildingDisplayList) { + aAutoBuildingDisplayList->emplace(aBuilder, aFrame); + } + if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) { needBlendContainer = true; } @@ -2764,8 +2769,8 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (!aBuilder->IsForEventDelivery()) { const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i]; - SetBackgroundClipRegion(clipState, aFrame, toRef, - layer, bgRect, willPaintBorder); + SetBackgroundClipRegion(clipState, aFrame, layer, bgRect, + willPaintBorder); } nsDisplayList thisItemList; diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 3aeb20d196..ff2a14dd77 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -48,6 +48,7 @@ class nsISelection; class nsIScrollableFrame; class nsDisplayLayerEventRegions; class nsDisplayScrollInfoLayer; +class nsDisplayTableBackgroundSet; class nsCaret; namespace mozilla { @@ -588,6 +589,16 @@ public: mSyncDecodeImages = aSyncDecodeImages; } + nsDisplayTableBackgroundSet* SetTableBackgroundSet( + nsDisplayTableBackgroundSet* aTableSet) { + nsDisplayTableBackgroundSet* old = mTableBackgroundSet; + mTableBackgroundSet = aTableSet; + return old; + } + nsDisplayTableBackgroundSet* GetTableBackgroundSet() const { + return mTableBackgroundSet; + } + /** * Helper method to generate background painting flags based on the * information available in the display list builder. Currently only @@ -711,6 +722,10 @@ public: class AutoBuildingDisplayList { public: + AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild) + : AutoBuildingDisplayList( + aBuilder, aForChild, aBuilder->GetDirtyRect(), aForChild->IsTransformed()){} + AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild, const nsRect& aDirtyRect, bool aIsRoot) : mBuilder(aBuilder), @@ -992,10 +1007,6 @@ public: return mPreserves3DCtx.mAccumulatedRectLevels; } - // Helpers for tables - nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; } - void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; } - struct OutOfFlowDisplayData { OutOfFlowDisplayData(const DisplayItemClip* aContainingBlockClip, const DisplayItemScrollClip* aContainingBlockScrollClip, @@ -1213,7 +1224,6 @@ private: AutoTArray<PresShellState,8> mPresShellStates; AutoTArray<nsIFrame*,400> mFramesMarkedForDisplay; AutoTArray<ThemeGeometry,2> mThemeGeometries; - nsDisplayTableItem* mCurrentTableItem; DisplayListClipState mClipState; // mCurrentFrame is the frame that we're currently calling (or about to call) // BuildDisplayList on. @@ -1256,6 +1266,7 @@ private: nsTArray<DisplayItemScrollClip*> mScrollClipsToDestroy; nsTArray<DisplayItemClip*> mDisplayItemClipsToDestroy; nsDisplayListBuilderMode mMode; + nsDisplayTableBackgroundSet* mTableBackgroundSet; ViewID mCurrentScrollParentId; ViewID mCurrentScrollbarTarget; uint32_t mCurrentScrollbarFlags; @@ -2751,7 +2762,9 @@ public: bool aAllowWillPaintBorderOptimization = true, nsStyleContext* aStyleContext = nullptr, const nsRect& aBackgroundOriginRect = nsRect(), - nsIFrame* aSecondaryReferenceFrame = nullptr); + nsIFrame* aSecondaryReferenceFrame = nullptr, + mozilla::Maybe<nsDisplayListBuilder::AutoBuildingDisplayList>* + aAutoBuildingDisplayList = nullptr); virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 096031385b..5372acb7fb 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -263,8 +263,8 @@ nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder, nsDisplayButtonBoxShadowOuter(aBuilder, this)); } - nsRect buttonRect; - GetButtonRect(mFrame->GetRectRelativeToSelf(), buttonRect); + nsRect buttonRect = + mFrame->GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(mFrame); nsDisplayBackgroundImage::AppendBackgroundItemsToTop( aBuilder, mFrame, buttonRect, aBackground); diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index ccab0faf5a..a5177560de 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -165,9 +165,11 @@ nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayBoxShadowOuter(aBuilder, this)); } + const nsRect rect = + VisualBorderRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); + nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, this, VisualBorderRectRelativeToSelf(), - aLists.BorderBackground(), + aBuilder, this, rect, aLists.BorderBackground(), /* aAllowWillPaintBorderOptimization = */ false); aLists.BorderBackground()->AppendNewToTop(new (aBuilder) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index c8415a7e70..8ba0bbf124 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; } @@ -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)); } @@ -2626,8 +2637,33 @@ static bool DescendIntoChild(nsDisplayListBuilder* aBuilder, 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, @@ -2770,7 +2806,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // If you change this, also change IsPseudoStackingContextFromStyle() pseudoStackingContext = true; } - + NS_ASSERTION(!isStackingContext || pseudoStackingContext, "Stacking contexts must also be pseudo-stacking-contexts"); diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 507e32b22d..4b02a52d8d 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -1992,7 +1992,8 @@ nsMathMLChar::Display(nsDisplayListBuilder* aBuilder, if (styleContext != parentContext && NS_GET_A(backg->mBackgroundColor) > 0) { nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, aForFrame, mRect, aLists.BorderBackground(), + aBuilder, aForFrame, mRect + aBuilder->ToReferenceFrame(aForFrame), + aLists.BorderBackground(), /* aAllowWillPaintBorderOptimization */ true, styleContext); } //else diff --git a/layout/reftests/position-relative/1409114-1-ref.html b/layout/reftests/position-relative/1409114-1-ref.html new file mode 100644 index 0000000000..7668cbdef6 --- /dev/null +++ b/layout/reftests/position-relative/1409114-1-ref.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html> +<body> +<table> + <col style="background:green"> + <tr> + <td style="width:20px; height:20px"></td> + </tr> +</table> +</body> + +</html>
\ No newline at end of file diff --git a/layout/reftests/position-relative/1409114-1.html b/layout/reftests/position-relative/1409114-1.html new file mode 100644 index 0000000000..1b984ab0c3 --- /dev/null +++ b/layout/reftests/position-relative/1409114-1.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<body> +<table> + <col style="background:green"> + <tr> + <td style="position:relative; left:-100px; width:20px; height:20px"></td> + </tr> +</table> +</body> +</html>
\ No newline at end of file diff --git a/layout/reftests/position-relative/1409114-2.html b/layout/reftests/position-relative/1409114-2.html new file mode 100644 index 0000000000..de18ed40db --- /dev/null +++ b/layout/reftests/position-relative/1409114-2.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<body style="overflow:hidden"> +<table style="position:relative; top:-50px"> + <col style="background:green; width: 40px;"> + <tr style="position:relative; left:-100px; height: 40px"> + <td rowspan=2></td> + </tr> + <tr style="height: 40px"></tr> +</table> +</body> + +</html>
\ No newline at end of file diff --git a/layout/reftests/position-relative/1409114-3.html b/layout/reftests/position-relative/1409114-3.html new file mode 100644 index 0000000000..3dc66122f1 --- /dev/null +++ b/layout/reftests/position-relative/1409114-3.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<body style="overflow:hidden"> +<table style="position:relative; top:-50px"> + <tbody style="background:green"> + <tr style="position:relative; left:-100px; height: 40px"> + <td rowspan=2 style="width: 40px;"></td> + </tr> + <tr style="height: 40px"></tr> + </tbody> +</table> +</body> +</html>
\ No newline at end of file diff --git a/layout/reftests/position-relative/reftest.list b/layout/reftests/position-relative/reftest.list index 880a38e8d5..495588ab79 100644 --- a/layout/reftests/position-relative/reftest.list +++ b/layout/reftests/position-relative/reftest.list @@ -7,3 +7,6 @@ == table-separate-3.html table-separate-3-ref.html == table-separate-4.html table-separate-4-ref.html == 1115999-1.html 1115999-1-ref.html +== 1409114-1.html 1409114-1-ref.html +!= 1409114-2.html about:blank +!= 1409114-3.html about:blank diff --git a/layout/reftests/table-background/border-collapse-opacity-table-column-group-ref.html b/layout/reftests/table-background/border-collapse-opacity-table-column-group-ref.html index bb03f15257..9ec969236a 100644 --- a/layout/reftests/table-background/border-collapse-opacity-table-column-group-ref.html +++ b/layout/reftests/table-background/border-collapse-opacity-table-column-group-ref.html @@ -10,8 +10,6 @@ html, body { margin: 0; padding: 0; border: 0; font-size: 16px; } body { padding: 15px; } - .o { opacity: 0.5; } - /* table { margin: 0px 3px 2px 4px; @@ -55,8 +53,8 @@ </head> <body> -<div class="color o"></div> -<div class="imagetl o"></div> +<div class="color"></div> +<div class="imagetl"></div> <div class="imagebr"></div> </body> diff --git a/layout/reftests/table-background/border-collapse-opacity-table-column-ref.html b/layout/reftests/table-background/border-collapse-opacity-table-column-ref.html index 7b7df902e5..82795ef8be 100644 --- a/layout/reftests/table-background/border-collapse-opacity-table-column-ref.html +++ b/layout/reftests/table-background/border-collapse-opacity-table-column-ref.html @@ -10,8 +10,6 @@ html, body { margin: 0; padding: 0; border: 0; font-size: 16px; } body { padding: 15px; } - .o { opacity: 0.5; } - /* table { margin: 0px 3px 2px 4px; @@ -55,8 +53,8 @@ </head> <body> -<div class="color o"></div> -<div class="imagetl o"></div> +<div class="color"></div> +<div class="imagetl"></div> <div class="imagebr"></div> </body> diff --git a/layout/reftests/table-background/border-separate-opacity-table-column-group-ref.html b/layout/reftests/table-background/border-separate-opacity-table-column-group-ref.html index ad6ca24539..6985dae64d 100644 --- a/layout/reftests/table-background/border-separate-opacity-table-column-group-ref.html +++ b/layout/reftests/table-background/border-separate-opacity-table-column-group-ref.html @@ -10,8 +10,6 @@ html, body { margin: 0; padding: 0; border: 0; font-size: 16px; } body { padding: 15px; } - .o { opacity: 0.5; } - /* table { margin: 0px 3px 2px 4px; @@ -65,8 +63,8 @@ <body> <div class="color"></div> -<div class="imagetl o"></div> -<div class="imagebr o"></div> +<div class="imagetl"></div> +<div class="imagebr"></div> <div class="hstripe" style="top: 46px"></div> <div class="hstripe" style="top: 70px"></div> diff --git a/layout/reftests/table-background/border-separate-opacity-table-column-ref.html b/layout/reftests/table-background/border-separate-opacity-table-column-ref.html index e00193dc3a..a6629347d2 100644 --- a/layout/reftests/table-background/border-separate-opacity-table-column-ref.html +++ b/layout/reftests/table-background/border-separate-opacity-table-column-ref.html @@ -10,8 +10,6 @@ html, body { margin: 0; padding: 0; border: 0; font-size: 16px; } body { padding: 15px; } - .o { opacity: 0.5; } - /* table { margin: 0px 3px 2px 4px; @@ -65,8 +63,8 @@ <body> <div class="color"></div> -<div class="imagetl o"></div> -<div class="imagebr o"></div> +<div class="imagetl"></div> +<div class="imagebr"></div> <div class="hstripe" style="top: 46px"></div> <div class="hstripe" style="top: 70px"></div> diff --git a/layout/reftests/table-background/reftest.list b/layout/reftests/table-background/reftest.list index 68dc43e956..a89115ef44 100644 --- a/layout/reftests/table-background/reftest.list +++ b/layout/reftests/table-background/reftest.list @@ -60,3 +60,6 @@ fuzzy-if(d2d||skiaContent,1,95000) == border-separate-opacity-table.html border- == empty-cells-default-2.html empty-cells-default-2-ref.html fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(Android,1,39) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,84,5500) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html == table-row-opacity-dynamic-2.html table-row-opacity-dynamic-2-ref.html + +== table-col-overlapping.html table-col-overlapping-ref.html +== table-col-span-1.html table-col-span-1-ref.html diff --git a/layout/reftests/table-background/table-col-overlapping-ref.html b/layout/reftests/table-background/table-col-overlapping-ref.html new file mode 100644 index 0000000000..37515fa283 --- /dev/null +++ b/layout/reftests/table-background/table-col-overlapping-ref.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<style> + td { + width: 20px; + height: 20px; + background-color: green; + } + table { + border-collapse:separate; + border-spacing: 0px; + } +</style> +</head> +<body> +<table> + <tr> + <td></td> + <td style="background-color: blue"></td> + <tr> + <td></td> + <td></td> + </tr> +</table> +</body> + +</html>
\ No newline at end of file diff --git a/layout/reftests/table-background/table-col-overlapping.html b/layout/reftests/table-background/table-col-overlapping.html new file mode 100644 index 0000000000..69acab789a --- /dev/null +++ b/layout/reftests/table-background/table-col-overlapping.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<style> + td { + width: 20px; + height: 20px; + } + table { + border-collapse:separate; + border-spacing: 0px; + } +</style> +</head> +<body> +<table> + <col style="background: green"></col> + <col style="background: blue"></col> + <tr> + <td></td> + <td rowspan=2></td> + <tr> + <td colspan=2></td> + </tr> +</table> +</body> + +</html>
\ No newline at end of file diff --git a/layout/reftests/table-background/table-col-span-1-ref.html b/layout/reftests/table-background/table-col-span-1-ref.html new file mode 100644 index 0000000000..dfe953ea44 --- /dev/null +++ b/layout/reftests/table-background/table-col-span-1-ref.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<body> + <table border> + <col style="background:purple"></col> + <col style="background:purple"></col> + <col style="background:blue"></col> + <tr> + <td>x</td> + <td>y</td> + <td>z</td> + </tr> + </table> +</body> +</html>
\ No newline at end of file diff --git a/layout/reftests/table-background/table-col-span-1.html b/layout/reftests/table-background/table-col-span-1.html new file mode 100644 index 0000000000..ee9f62d7e9 --- /dev/null +++ b/layout/reftests/table-background/table-col-span-1.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<body> + <table border> + <col span=2 style="background:purple"></col> + <col style="background:blue"></col> + <tr> + <td>x</td> + <td>y</td> + <td>z</td> + </tr> + </table> +</body> + +</html>
\ No newline at end of file diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 64e7d2cfe6..9c715d999b 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -461,14 +461,14 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); } + nsRect bgRect = GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); + // display background if we need to. if (aBuilder->IsForEventDelivery() || !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) { - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, - this, - GetRectRelativeToSelf(), - aLists.BorderBackground()); + nsDisplayBackgroundImage::AppendBackgroundItemsToTop( + aBuilder, this, bgRect, aLists.BorderBackground()); } // display inset box-shadows if we need to. @@ -487,16 +487,49 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, "TableCellSelection", nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); } + + // This can be null if display list building initiated in the middle + // of the table, which can happen with background-clip:text and + // -moz-element. + nsDisplayTableBackgroundSet* backgrounds = + aBuilder->GetTableBackgroundSet(); + if (backgrounds) { + // Compute bgRect relative to reference frame, but using the + // normal (without position:relative offsets) positions for the + // cell, row and row group. + bgRect = GetRectRelativeToSelf() + GetNormalPosition(); + + nsTableRowFrame* row = GetTableRowFrame(); + bgRect += row->GetNormalPosition(); + + nsTableRowGroupFrame* rowGroup = row->GetTableRowGroupFrame(); + bgRect += rowGroup->GetNormalPosition(); + + bgRect += backgrounds->TableToReferenceFrame(); + + // Create backgrounds items as needed for the column and column + // group that this cell occupies. + nsTableColFrame* col = backgrounds->GetColForIndex(ColIndex()); + nsTableColGroupFrame* colGroup = col->GetTableColGroupFrame(); + + Maybe<nsDisplayListBuilder::AutoBuildingDisplayList> buildingForColGroup; + nsDisplayBackgroundImage::AppendBackgroundItemsToTop( + aBuilder, colGroup, bgRect, backgrounds->ColGroupBackgrounds(), false, + nullptr, colGroup->GetRect() + backgrounds->TableToReferenceFrame(), + this, &buildingForColGroup); + + Maybe<nsDisplayListBuilder::AutoBuildingDisplayList> buildingForCol; + nsDisplayBackgroundImage::AppendBackgroundItemsToTop( + aBuilder, col, bgRect, backgrounds->ColBackgrounds(), false, nullptr, + col->GetRect() + colGroup->GetPosition() + + backgrounds->TableToReferenceFrame(), + this, &buildingForCol); + } } // the 'empty-cells' property has no effect on 'outline' DisplayOutline(aBuilder, aLists); - // Push a null 'current table item' so that descendant tables can't - // accidentally mess with our table - nsAutoPushCurrentTableItem pushTableItem; - pushTableItem.Push(aBuilder, nullptr); - nsIFrame* kid = mFrames.FirstChild(); NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child"); // The child's background will go in our BorderBackground() list. diff --git a/layout/tables/nsTableColFrame.cpp b/layout/tables/nsTableColFrame.cpp index 659f0fd352..6723f4701a 100644 --- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -112,7 +112,13 @@ void nsTableColFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { - nsTableFrame::DisplayGenericTablePart(aBuilder, this, 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 and box-shadows fall into this category, so we skip them + // on these boxes. + + MOZ_ASSERT_UNREACHABLE("Cols don't paint themselves"); } int32_t nsTableColFrame::GetSpan() diff --git a/layout/tables/nsTableColGroupFrame.cpp b/layout/tables/nsTableColGroupFrame.cpp index 7327834289..be5b71bb24 100644 --- a/layout/tables/nsTableColGroupFrame.cpp +++ b/layout/tables/nsTableColGroupFrame.cpp @@ -387,7 +387,13 @@ void nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { - nsTableFrame::DisplayGenericTablePart(aBuilder, this, 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 and box-shadows fall into this category, so we skip them + // on these boxes. + + MOZ_ASSERT_UNREACHABLE("Colgroups don't paint themselves"); } nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 57b249fb32..59a6d0f1ab 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1166,113 +1166,7 @@ nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder, static_cast<nsTableFrame*>(mFrame)->PaintBCBorders(*drawTarget, mVisibleRect - pt); } -/* static */ void -nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, - const nsDisplayListSet& aLists) -{ - // This is similar to what nsContainerFrame::BuildDisplayListForNonBlockChildren - // does, except that we allow the children's background and borders to go - // in our BorderBackground list. This doesn't really affect background - // painting --- the children won't actually draw their own backgrounds - // because the nsTableFrame already drew them, unless a child has its own - // stacking context, in which case the child won't use its passed-in - // BorderBackground list anyway. It does affect cell borders though; this - // lets us get cell borders into the nsTableFrame's BorderBackground list. - for (nsIFrame* kid : aFrame->GetChildList(kColGroupList)) { - aFrame->BuildDisplayListForChild(aBuilder, kid, aLists); - } - - for (nsIFrame* kid : aFrame->PrincipalChildList()) { - aFrame->BuildDisplayListForChild(aBuilder, kid, aLists); - } -} - -static void -PaintRowBackground(nsTableRowFrame* aRow, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists, - const nsPoint& aOffset = nsPoint()) -{ - // Compute background rect by iterating over all cell frames. - for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) { - if (!cell->ShouldPaintBackground(aBuilder)) { - continue; - } - - auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; - if (!aBuilder->GetDirtyRect().Intersects(cellRect)) { - continue; - } - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, - aLists.BorderBackground(), - true, nullptr, - aFrame->GetRectRelativeToSelf(), - cell); - } -} - -static void -PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists) -{ - for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { - if (!aBuilder->GetDirtyRect().Intersects(nsRect(row->GetNormalPosition(), - row->GetSize()))) { - continue; - } - PaintRowBackground(row, aFrame, aBuilder, aLists, row->GetNormalPosition()); - } -} - -static void -PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists, - const nsTArray<uint32_t>& aColIdx, - const nsPoint& aOffset) -{ - MOZ_DIAGNOSTIC_ASSERT(!aColIdx.IsEmpty(), - "Must be painting backgrounds for something"); - for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { - auto rowPos = row->GetNormalPosition() + aOffset; - if (!aBuilder->GetDirtyRect().Intersects(nsRect(rowPos, row->GetSize()))) { - continue; - } - for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { - - uint32_t curColIdx = cell->ColIndex(); - if (!aColIdx.Contains(curColIdx)) { - if (curColIdx > aColIdx.LastElement()) { - // We can just stop looking at this row. - break; - } - continue; - } - - if (!cell->ShouldPaintBackground(aBuilder)) { - continue; - } - - auto cellPos = cell->GetNormalPosition() + rowPos; - auto cellRect = nsRect(cellPos, cell->GetSize()); - if (!aBuilder->GetDirtyRect().Intersects(cellRect)) { - continue; - } - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, - aLists.BorderBackground(), - true, nullptr, - aFrame->GetRectRelativeToSelf(), - cell); - } - } -} - -static inline bool FrameHasBorder(nsIFrame* f) -{ +static inline bool FrameHasBorder(nsIFrame* f) { if (!f->StyleVisibility()->IsVisible()) { return false; } @@ -1284,8 +1178,7 @@ static inline bool FrameHasBorder(nsIFrame* f) return false; } -void nsTableFrame::CalcHasBCBorders() -{ +void nsTableFrame::CalcHasBCBorders() { if (!IsBorderCollapse()) { SetHasBCBorders(false); return; @@ -1303,8 +1196,9 @@ void nsTableFrame::CalcHasBCBorders() return; } - nsTableColGroupFrame *colGroup = static_cast<nsTableColGroupFrame*>(f); - for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { + nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(f); + for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; + col = col->GetNextCol()) { if (FrameHasBorder(col)) { SetHasBCBorders(true); return; @@ -1321,13 +1215,15 @@ void nsTableFrame::CalcHasBCBorders() return; } - for (nsTableRowFrame* row = rowGroup->GetFirstRow(); row; row = row->GetNextRow()) { + for (nsTableRowFrame* row = rowGroup->GetFirstRow(); row; + row = row->GetNextRow()) { if (FrameHasBorder(row)) { SetHasBCBorders(true); return; } - for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { + for (nsTableCellFrame* cell = row->GetFirstCell(); cell; + cell = cell->GetNextCell()) { if (FrameHasBorder(cell)) { SetHasBCBorders(true); return; @@ -1339,138 +1235,58 @@ void nsTableFrame::CalcHasBCBorders() SetHasBCBorders(false); } -/* static */ void -nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, - nsFrame* aFrame, - const nsDisplayListSet& aLists, - DisplayGenericTablePartTraversal aTraversal) -{ - bool isVisible = aFrame->IsVisibleForPainting(aBuilder); - bool isTable = (aFrame->GetType() == nsGkAtoms::tableFrame); - - if (isVisible || !isTable) { - nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); - // currentItem may be null, when none of the table parts have a - // background or border - if (currentItem) { - currentItem->UpdateForFrameBackground(aFrame); - } - } - - if (isVisible) { - // XXX: should box-shadow for rows/rowgroups/columns/colgroups get painted - // just because we're visible? Or should it depend on the cell visibility - // when we're not the whole table? - - // Paint the outset box-shadows for the table frames - if (aFrame->StyleEffects()->mBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame)); - } - } - - // Background visibility for rows, rowgroups, columns, colgroups depends on - // the visibility of the _cell_, not of the row/col(group). - // See spec at https://drafts.csswg.org/css-tables-3/#drawing-cell-backgrounds - if (aFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { - nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame); - PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); - } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) { - nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame); - PaintRowBackground(row, aFrame, aBuilder, aLists); - } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) { - // Compute background rect by iterating all cell frame. - nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame); - // Collecting column index. - AutoTArray<uint32_t, 1> colIdx; - for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { - MOZ_ASSERT(colIdx.IsEmpty() || - static_cast<uint32_t>(col->GetColIndex()) > colIdx.LastElement()); - colIdx.AppendElement(col->GetColIndex()); - } - - if (!colIdx.IsEmpty()) { - // We have some actual cells that live inside this rowgroup. - nsTableFrame* table = colGroup->GetTableFrame(); - RowGroupArray rowGroups; - table->OrderRowGroups(rowGroups); - for (nsTableRowGroupFrame* rowGroup : rowGroups) { - auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition(); - if (!aBuilder->GetDirtyRect().Intersects(nsRect(offset, rowGroup->GetSize()))) { - continue; - } - PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); - } - } - } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) { - // Compute background rect by iterating all cell frame. - nsTableColFrame* col = static_cast<nsTableColFrame*>(aFrame); - AutoTArray<uint32_t, 1> colIdx; - colIdx.AppendElement(col->GetColIndex()); +// table paint code is concerned primarily with borders and bg color +// SEC: TODO: adjust the rect for captions +void +nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists) +{ + DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255)); - nsTableFrame* table = col->GetTableFrame(); - RowGroupArray rowGroups; - table->OrderRowGroups(rowGroups); - for (nsTableRowGroupFrame* rowGroup : rowGroups) { - auto offset = rowGroup->GetNormalPosition() - - col->GetNormalPosition() - - col->GetTableColGroupFrame()->GetNormalPosition(); - if (!aBuilder->GetDirtyRect().Intersects(nsRect(offset, rowGroup->GetSize()))) { - continue; - } - PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); - } - } else if (isVisible) { - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, - aFrame->GetRectRelativeToSelf(), - aLists.BorderBackground()); - } + DisplayBorderBackgroundOutline(aBuilder, aLists); - if (isVisible) { - // XXX: should box-shadow for rows/rowgroups/columns/colgroups get painted - // just because we're visible? Or should it depend on the cell visibility - // when we're not the whole table? + nsDisplayTableBackgroundSet tableBGs(aBuilder, this); + nsDisplayListCollection lists(aBuilder); - // Paint the inset box-shadows for the table frames - if (aFrame->StyleEffects()->mBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame)); +// This is similar to what + // nsContainerFrame::BuildDisplayListForNonBlockChildren does, except that we + // allow the children's background and borders to go in our BorderBackground + // list. This doesn't really affect background painting --- the children won't + // actually draw their own backgrounds because the nsTableFrame already drew + // them, unless a child has its own stacking context, in which case the child + // won't use its passed-in BorderBackground list anyway. It does affect cell + // borders though; this lets us get cell borders into the nsTableFrame's + // BorderBackground list. + for (nsIFrame* colGroup : FirstContinuation()->GetChildList(kColGroupList)) { + for (nsIFrame* col : colGroup->PrincipalChildList()) { + tableBGs.AddColumn((nsTableColFrame*)col); } } - aTraversal(aBuilder, aFrame, aLists); + for (nsIFrame* kid : PrincipalChildList()) { + BuildDisplayListForChild(aBuilder, kid, lists); + } - if (isVisible) { - if (isTable) { - nsTableFrame* table = static_cast<nsTableFrame*>(aFrame); - // In the collapsed border model, overlay all collapsed borders. - if (table->IsBorderCollapse()) { - if (table->HasBCBorders()) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table)); - } - } else { - const nsStyleBorder* borderStyle = aFrame->StyleBorder(); - if (borderStyle->HasBorder()) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBorder(aBuilder, table)); - } + tableBGs.MoveTo(aLists); + lists.MoveTo(aLists); + + if (IsVisibleForPainting(aBuilder)) { + // In the collapsed border model, overlay all collapsed borders. + if (IsBorderCollapse()) { + if (HasBCBorders()) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayTableBorderCollapse + (aBuilder, this)); + } + } else { + const nsStyleBorder* borderStyle = StyleBorder(); + if (borderStyle->HasBorder()) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBorder + (aBuilder, this)); } } } - - aFrame->DisplayOutline(aBuilder, aLists); -} - -// table paint code is concerned primarily with borders and bg color -// SEC: TODO: adjust the rect for captions -void -nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists) -{ - DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255)); - - DisplayGenericTablePart(aBuilder, this, aLists); } nsMargin diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 8a23841345..7fcdcb9d87 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -72,36 +72,59 @@ private: bool mDrawsBackground; }; -class nsAutoPushCurrentTableItem -{ -public: - nsAutoPushCurrentTableItem() : mBuilder(nullptr) {} +class nsDisplayTableBackgroundSet { + public: + nsDisplayList* ColGroupBackgrounds() { return &mColGroupBackgrounds; } + + nsDisplayList* ColBackgrounds() { return &mColBackgrounds; } + + nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable) + : mBuilder(aBuilder) { + mPrevTableBackgroundSet = mBuilder->SetTableBackgroundSet(this); + mozilla::DebugOnly<const nsIFrame*> reference = + mBuilder->FindReferenceFrameFor(aTable, &mToReferenceFrame); + MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(reference, aTable)); + mDirtyRect = mBuilder->GetDirtyRect(); + } - void Push(nsDisplayListBuilder* aBuilder, nsDisplayTableItem* aPushItem) - { - mBuilder = aBuilder; - mOldCurrentItem = aBuilder->GetCurrentTableItem(); - aBuilder->SetCurrentTableItem(aPushItem); -#ifdef DEBUG - mPushedItem = aPushItem; -#endif + ~nsDisplayTableBackgroundSet() { + mozilla::DebugOnly<nsDisplayTableBackgroundSet*> result = + mBuilder->SetTableBackgroundSet(mPrevTableBackgroundSet); + MOZ_ASSERT(result == this); } - ~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); + + /** + * Move all display items in our lists to top of the corresponding lists in + * the destination. + */ + void MoveTo(const nsDisplayListSet& aDestination) { + aDestination.BorderBackground()->AppendToTop(ColGroupBackgrounds()); + aDestination.BorderBackground()->AppendToTop(ColBackgrounds()); } -private: + void AddColumn(nsTableColFrame* aFrame) { mColumns.AppendElement(aFrame); } + + nsTableColFrame* GetColForIndex(int32_t aIndex) { return mColumns[aIndex]; } + + const nsPoint& TableToReferenceFrame() { return mToReferenceFrame; } + + const nsRect& GetDirtyRect() { return mDirtyRect; } + + 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! + void* operator new(size_t sz) CPP_THROW_NEW; + + protected: nsDisplayListBuilder* mBuilder; - nsDisplayTableItem* mOldCurrentItem; -#ifdef DEBUG - nsDisplayTableItem* mPushedItem; -#endif + nsDisplayTableBackgroundSet* mPrevTableBackgroundSet; + + nsDisplayList mColGroupBackgrounds; + nsDisplayList mColBackgrounds; + + nsTArray<nsTableColFrame*> mColumns; + nsPoint mToReferenceFrame; + nsRect mDirtyRect; }; /* ============================================================================ */ @@ -229,28 +252,6 @@ public: nsIFrame* aSourceFrame, bool* aDidPassThrough); - typedef void (* DisplayGenericTablePartTraversal) - (nsDisplayListBuilder* aBuilder, nsFrame* aFrame, - const nsDisplayListSet& aLists); - static void GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, - const nsDisplayListSet& aLists); - - /** - * Helper method to handle display common to table frames, rowgroup frames - * 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 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. - */ - static void DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, - nsFrame* aFrame, - const nsDisplayListSet& aLists, - DisplayGenericTablePartTraversal aTraversal = GenericTraversal); - // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. static nsIFrame* GetFrameAtOrBefore(nsIFrame* aParentFrame, diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 685f4fdeae..18f11f876b 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -549,11 +549,66 @@ nsTableRowFrame::CalcBSize(const ReflowInput& aReflowInput) return GetInitialBSize(); } +void nsTableRowFrame::PaintCellBackgroundsForFrame( + nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists, const nsPoint& aOffset) { + // Compute background rect by iterating all cell frame. + const nsPoint toReferenceFrame = aBuilder->ToReferenceFrame(aFrame); + for (nsTableCellFrame* cell = GetFirstCell(); cell; + cell = cell->GetNextCell()) { + if (!cell->ShouldPaintBackground(aBuilder)) { + continue; + } + + auto cellRect = + cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; + if (!aBuilder->GetDirtyRect().Intersects(cellRect)) { + continue; + } + cellRect += toReferenceFrame; + nsDisplayBackgroundImage::AppendBackgroundItemsToTop( + aBuilder, aFrame, cellRect, aLists.BorderBackground(), true, nullptr, + aFrame->GetRectRelativeToSelf() + toReferenceFrame, cell); + } +} + void nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { - nsTableFrame::DisplayGenericTablePart(aBuilder, this, aLists); + if (IsVisibleForPainting(aBuilder)) { + // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted + // just because we're visible? Or should it depend on the cell visibility + // when we're not the whole table? + + // Paint the outset box-shadows for the table frames + if (StyleEffects()->mBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowOuter + (aBuilder, this)); + } + } + + PaintCellBackgroundsForFrame(this, aBuilder, aLists); + + if (IsVisibleForPainting(aBuilder)) { + // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted + // just because we're visible? Or should it depend on the cell visibility + // when we're not the whole table? + + // Paint the inset box-shadows for the table frames + if (StyleEffects()->mBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowInner + (aBuilder, this)); + } + } + + DisplayOutline(aBuilder, aLists); + + for (nsIFrame* kid : PrincipalChildList()) { + BuildDisplayListForChild(aBuilder, kid, aLists); + } } nsIFrame::LogicalSides diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 350b4f6f76..4b6dd2628c 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -81,6 +81,11 @@ public: virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) override; + void PaintCellBackgroundsForFrame(nsIFrame* aFrame, + nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists, + const nsPoint& aOffset = nsPoint()); + // Implemented in nsTableCellFrame.h, because it needs to know about the // nsTableCellFrame class, but we can't include nsTableCellFrame.h here. inline nsTableCellFrame* GetFirstCell() const; diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 1b7f029c89..b6d8a43647 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -207,8 +207,43 @@ void nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { - nsTableFrame::DisplayGenericTablePart(aBuilder, this, - aLists, DisplayRows); + if (IsVisibleForPainting(aBuilder)) { + // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted + // just because we're visible? Or should it depend on the cell visibility + // when we're not the whole table? + + // Paint the outset box-shadows for the table frames + if (StyleEffects()->mBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowOuter + (aBuilder, this)); + } + } + + for (nsTableRowFrame* row = GetFirstRow(); row; row = row->GetNextRow()) { + if (!aBuilder->GetDirtyRect().Intersects(row->GetVisualOverflowRect() + row->GetNormalPosition())) { + continue; + } + row->PaintCellBackgroundsForFrame(this, aBuilder, aLists, + row->GetNormalPosition()); + } + + if (IsVisibleForPainting(aBuilder)) { + // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted + // just because we're visible? Or should it depend on the cell visibility + // when we're not the whole table? + + // Paint the inset box-shadows for the table frames + if (StyleEffects()->mBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowInner + (aBuilder, this)); + } + } + + DisplayOutline(aBuilder, aLists); + + DisplayRows(aBuilder, this, aLists); } nsIFrame::LogicalSides diff --git a/layout/xul/nsGroupBoxFrame.cpp b/layout/xul/nsGroupBoxFrame.cpp index fcdc1d1905..df3955cf3e 100644 --- a/layout/xul/nsGroupBoxFrame.cpp +++ b/layout/xul/nsGroupBoxFrame.cpp @@ -149,7 +149,8 @@ nsGroupBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // Paint our background and border if (IsVisibleForPainting(aBuilder)) { nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, this, GetBackgroundRectRelativeToSelf(), + aBuilder, this, + GetBackgroundRectRelativeToSelf() + aBuilder->ToReferenceFrame(this), aLists.BorderBackground()); aLists.BorderBackground()->AppendNewToTop(new (aBuilder) nsDisplayXULGroupBorder(aBuilder, this)); |