author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Thu, 04 May 2017 17:00:20 +0200 | |
changeset 356503 | 3f788935a3a4c1c6b65729298c497f06687f52ad |
parent 356502 | 5d9cdb47c1b93d649ec3437a0c6d545d058ca672 |
child 356504 | 9499b714afc482732c2fa3da54b353f79a2322b8 |
push id | 89910 |
push user | cbook@mozilla.com |
push date | Thu, 04 May 2017 15:00:30 +0000 |
treeherder | mozilla-inbound@3f788935a3a4 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 929484 |
milestone | 55.0a1 |
backs out | 93acd240b5782a90f1ce9bd4059f64907fa98137 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/layout/painting/nsDisplayItemTypesList.h +++ b/layout/painting/nsDisplayItemTypesList.h @@ -54,17 +54,16 @@ DECLARE_DISPLAY_ITEM_TYPE(FILTER) DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG) DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY) DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT) DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION) DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_GROUP_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_BACKGROUND) -DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE) DECLARE_DISPLAY_ITEM_TYPE(TEXT) DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW) DECLARE_DISPLAY_ITEM_TYPE_FLAGS(TRANSFORM,TYPE_RENDERS_NO_IMAGES) DECLARE_DISPLAY_ITEM_TYPE_FLAGS(PERSPECTIVE,TYPE_RENDERS_NO_IMAGES) DECLARE_DISPLAY_ITEM_TYPE(VIDEO) DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST) DECLARE_DISPLAY_ITEM_TYPE(ZOOM)
--- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -3057,26 +3057,21 @@ SpecialCutoutRegionCase(nsDisplayListBui /*static*/ bool nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const nsRect& aBackgroundRect, nsDisplayList* aList, bool aAllowWillPaintBorderOptimization, - nsStyleContext* aStyleContext, - const nsRect& aBackgroundOriginRect) + nsStyleContext* aStyleContext) { nsStyleContext* bgSC = aStyleContext; const nsStyleBackground* bg = nullptr; nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame); - nsRect bgOriginRect = bgRect; - if (!aBackgroundOriginRect.IsEmpty()) { - bgOriginRect = aBackgroundOriginRect + aBuilder->ToReferenceFrame(aFrame); - } nsPresContext* presContext = aFrame->PresContext(); bool isThemed = aFrame->IsThemed(); if (!isThemed) { if (!bgSC) { bgSC = GetBackgroundStyleContext(aFrame); } if (bgSC) { bg = bgSC->StyleBackground(); @@ -3175,17 +3170,17 @@ nsDisplayBackgroundImage::AppendBackgrou if (!aBuilder->IsForEventDelivery()) { const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i]; SetBackgroundClipRegion(clipState, aFrame, toRef, layer, bgRect, willPaintBorder); } nsDisplayList thisItemList; nsDisplayBackgroundImage::InitData bgData = - nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgOriginRect, bg, + nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgRect, bg, LayerizeFixed::DO_NOT_LAYERIZE_FIXED_BACKGROUND_IF_AVOIDING_COMPONENT_ALPHA_LAYERS); if (bgData.shouldFixToViewport) { auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData(); nsDisplayListBuilder::AutoBuildingDisplayList buildingDisplayList(aBuilder, aFrame, aBuilder->GetDirtyRect(), false);
--- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -3066,18 +3066,17 @@ public: // aAllowWillPaintBorderOptimization should usually be left at true, unless // aFrame has special border drawing that causes opaque borders to not // actually be opaque. static bool AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const nsRect& aBackgroundRect, nsDisplayList* aList, bool aAllowWillPaintBorderOptimization = true, - nsStyleContext* aStyleContext = nullptr, - const nsRect& aBackgroundOriginRect = nsRect()); + nsStyleContext* aStyleContext = nullptr); virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aParameters) override; virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) override;
--- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -485,61 +485,81 @@ PaintTableCellSelection(nsIFrame* aFrame } void nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame"); - nsTableFrame* tableFrame = GetTableFrame(); - int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? - StyleTableBorder()->mEmptyCells - : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; - // take account of 'empty-cells' - if (StyleVisibility()->IsVisible() && - (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { - // display outset box-shadows if we need to. - bool hasBoxShadow = !!StyleEffects()->mBoxShadow; - if (hasBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); + if (IsVisibleInSelection(aBuilder)) { + nsTableFrame* tableFrame = GetTableFrame(); + int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? + StyleTableBorder()->mEmptyCells + : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; + // take account of 'empty-cells' + if (StyleVisibility()->IsVisible() && + (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { + // display outset box-shadows if we need to. + bool hasBoxShadow = !!StyleEffects()->mBoxShadow; + if (hasBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); + } + + // display background if we need to. + if (aBuilder->IsForEventDelivery() || + !StyleBackground()->IsTransparent(this) || + StyleDisplay()->UsedAppearance()) { + if (!tableFrame->IsBorderCollapse()) { + nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, + this, + GetRectRelativeToSelf(), + aLists.BorderBackground()); + } else if (aBuilder->IsAtRootOfPseudoStackingContext() || + aBuilder->IsForEventDelivery()) { + // 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 + nsDisplayTableItem* item = + new (aBuilder) nsDisplayTableCellBackground(aBuilder, this); + aLists.BorderBackground()->AppendNewToTop(item); + item->UpdateForFrameBackground(this); + } else { + // The nsTablePainter will paint our background. Make sure it + // knows if we're background-attachment:fixed. + nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); + if (currentItem) { + currentItem->UpdateForFrameBackground(this); + } + } + } + + // display inset box-shadows if we need to. + if (hasBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this)); + } + + // display borders if we need to + ProcessBorders(tableFrame, aBuilder, aLists); + + // and display the selection border if we need to + if (IsSelected()) { + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) + nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection, + "TableCellSelection", + nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); + } } - - // display background if we need to. - if (aBuilder->IsForEventDelivery() || - !StyleBackground()->IsTransparent(this) || - StyleDisplay()->UsedAppearance()) { - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, - this, - GetRectRelativeToSelf(), - aLists.BorderBackground()); - } - - // display inset box-shadows if we need to. - if (hasBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this)); - } - - // display borders if we need to - ProcessBorders(tableFrame, aBuilder, aLists); - - // and display the selection border if we need to - if (IsSelected()) { - aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection, - "TableCellSelection", - nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); - } + + // the 'empty-cells' property has no effect on 'outline' + DisplayOutline(aBuilder, aLists); } - // 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.
--- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -117,24 +117,16 @@ nsTableColFrame::Reflow(nsPresContext* bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); if (collapseCol) { GetTableFrame()->SetNeedToCollapse(true); } aStatus.Reset(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); } -void -nsTableColFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) -{ - nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); -} - int32_t nsTableColFrame::GetSpan() { return StyleTable()->mSpan; } #ifdef DEBUG void nsTableColFrame::Dump(int32_t aIndent) {
--- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -48,19 +48,22 @@ public: /** @see nsIFrame::DidSetStyleContext */ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override; virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) override; + /** + * Table columns never paint anything, nor receive events. + */ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) override; + const nsDisplayListSet& aLists) override {} #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif virtual nsSplittableType GetSplittableType() const override; nsTableColGroupFrame* GetTableColGroupFrame() const
--- a/layout/tables/nsTableColGroupFrame.cpp +++ b/layout/tables/nsTableColGroupFrame.cpp @@ -381,24 +381,16 @@ nsTableColGroupFrame::Reflow(nsPresConte FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, 0, 0, 0); } aDesiredSize.ClearSize(); aStatus.Reset(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); } -void -nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) -{ - nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); -} - nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() { return GetNextColumn(nullptr); } nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame) { nsTableColFrame *result = nullptr;
--- a/layout/tables/nsTableColGroupFrame.h +++ b/layout/tables/nsTableColGroupFrame.h @@ -45,19 +45,22 @@ public: { nsIFrame* parent = GetParent(); MOZ_ASSERT(parent && parent->IsTableFrame()); MOZ_ASSERT(!parent->GetPrevInFlow(), "Col group should always be in a first-in-flow table frame"); return static_cast<nsTableFrame*>(parent); } + /** + * ColGroups never paint anything, nor receive events. + */ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) override; + const nsDisplayListSet& aLists) override {} /** A colgroup can be caused by three things: * 1) An element with table-column-group display * 2) An element with a table-column display without a * table-column-group parent * 3) Cells that are not in a column (and hence get an anonymous * column and colgroup). * @return colgroup type
--- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1233,56 +1233,16 @@ nsDisplayTableItem::ComputeInvalidationR geometry->ShouldInvalidateToSyncDecodeImages())) { bool snap; aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap)); } nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); } -// A display item that draws all collapsed borders for a table. -// At some point, we may want to find a nicer partitioning for dividing -// border-collapse segments into their own display items. -class nsDisplayTableBorderCollapse : public nsDisplayTableItem { -public: - nsDisplayTableBorderCollapse(nsDisplayListBuilder* aBuilder, - nsTableFrame* aFrame) - : nsDisplayTableItem(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplayTableBorderCollapse); - } -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayTableBorderCollapse() { - MOZ_COUNT_DTOR(nsDisplayTableBorderCollapse); - } -#endif - - virtual void Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) override; - NS_DISPLAY_DECL_NAME("TableBorderCollapse", TYPE_TABLE_BORDER_COLLAPSE) -}; - -void -nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) -{ - nsPoint pt = ToReferenceFrame(); - DrawTarget* drawTarget = aCtx->GetDrawTarget(); - - gfxPoint devPixelOffset = - nsLayoutUtils::PointToGfxPoint(pt, mFrame->PresContext()->AppUnitsPerDevPixel()); - - // XXX we should probably get rid of this translation at some stage - // But that would mean modifying PaintBCBorders, ugh - AutoRestoreTransform autoRestoreTransform(drawTarget); - drawTarget->SetTransform( - drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset))); - - static_cast<nsTableFrame*>(mFrame)->PaintBCBorders(*drawTarget, mVisibleRect - pt); -} - class nsDisplayTableBorderBackground : public nsDisplayTableItem { public: nsDisplayTableBorderBackground(nsDisplayListBuilder* aBuilder, nsTableFrame* aFrame, bool aDrawsBackground) : nsDisplayTableItem(aBuilder, aFrame, aDrawsBackground) { MOZ_COUNT_CTOR(nsDisplayTableBorderBackground); } @@ -1292,185 +1252,136 @@ public: } #endif virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; NS_DISPLAY_DECL_NAME("TableBorderBackground", TYPE_TABLE_BORDER_BACKGROUND) }; +#ifdef DEBUG +static bool +IsFrameAllowedInTable(LayoutFrameType aType) +{ + return IS_TABLE_CELL(aType) || + LayoutFrameType::TableRow == aType || + LayoutFrameType::TableRowGroup == aType || + LayoutFrameType::Scroll == aType || + LayoutFrameType::Table == aType || + LayoutFrameType::TableCol == aType || + LayoutFrameType::TableColGroup == aType; +} +#endif + void nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { DrawResult result = static_cast<nsTableFrame*>(mFrame)-> PaintTableBorderBackground(aBuilder, *aCtx, mVisibleRect, ToReferenceFrame()); nsDisplayTableItemGeometry::UpdateDrawResult(this, result); } +static int32_t +GetTablePartRank(nsDisplayItem* aItem) +{ + LayoutFrameType type = aItem->Frame()->Type(); + if (type == LayoutFrameType::Table) + return 0; + if (type == LayoutFrameType::TableRowGroup) + return 1; + if (type == LayoutFrameType::TableRow) + return 2; + return 3; +} + +struct TablePartRankComparator { + bool operator()(nsDisplayItem* aItem1, nsDisplayItem* aItem2) const { + return GetTablePartRank(aItem1) < GetTablePartRank(aItem2); + } +}; + /* static */ void nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, 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, aDirtyRect, aLists); - } - for (nsIFrame* kid : aFrame->PrincipalChildList()) { aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); } } -static void -PaintRowBackground(nsTableRowFrame* aRow, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists, - const nsPoint& aOffset = nsPoint()) -{ - // Compute background rect by iterating all cell frame. - for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) { - auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, - aLists.BorderBackground(), - true, nullptr, - aFrame->GetRectRelativeToSelf()); - } -} - -static void -PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists) -{ - for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { - PaintRowBackground(row, aFrame, aBuilder, aLists, row->GetNormalPosition()); - } -} - -static void -PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists, - const nsTArray<int32_t>& aColIdx, - const nsPoint& aOffset) -{ - for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { - for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { - int32_t curColIdx; - cell->GetColIndex(curColIdx); - if (aColIdx.Contains(curColIdx)) { - auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + row->GetNormalPosition() + aOffset; - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, - aLists.BorderBackground(), - true, nullptr, - aFrame->GetRectRelativeToSelf()); - } - } - } -} - /* static */ void nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, + 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. + bool sortEventBackgrounds = aDisplayItem && aBuilder->IsForEventDelivery(); + nsDisplayListCollection separatedCollection; + const nsDisplayListSet* lists = sortEventBackgrounds ? &separatedCollection : &aLists; + + nsAutoPushCurrentTableItem pushTableItem; + if (aDisplayItem) { + pushTableItem.Push(aBuilder, aDisplayItem); + } + if (aFrame->IsVisibleForPainting(aBuilder)) { nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); // currentItem may be null, when none of the table parts have a // background or border if (currentItem) { currentItem->UpdateForFrameBackground(aFrame); } // Paint the outset box-shadows for the table frames bool hasBoxShadow = aFrame->StyleEffects()->mBoxShadow != nullptr; if (hasBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( + lists->BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame)); } - if (aFrame->IsTableRowGroupFrame()) { - nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame); - PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); - } else if (aFrame->IsTableRowFrame()) { - nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame); - PaintRowBackground(row, aFrame, aBuilder, aLists); - } else if (aFrame->IsTableColGroupFrame()) { - // Compute background rect by iterating all cell frame. - nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame); - // Collecting column index. - AutoTArray<int32_t, 1> colIdx; - for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { - colIdx.AppendElement(col->GetColIndex()); - } - - nsTableFrame* table = colGroup->GetTableFrame(); - RowGroupArray rowGroups; - table->OrderRowGroups(rowGroups); - for (nsTableRowGroupFrame* rowGroup : rowGroups) { - auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition(); - PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); - } - } else if (aFrame->IsTableColFrame()) { - // Compute background rect by iterating all cell frame. - nsTableColFrame* col = static_cast<nsTableColFrame*>(aFrame); - AutoTArray<int32_t, 1> colIdx; - colIdx.AppendElement(col->GetColIndex()); - - nsTableFrame* table = col->GetTableFrame(); - RowGroupArray rowGroups; - table->OrderRowGroups(rowGroups); - for (nsTableRowGroupFrame* rowGroup : rowGroups) { - auto offset = rowGroup->GetNormalPosition() - - col->GetNormalPosition() - - col->GetTableColGroupFrame()->GetNormalPosition(); - PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); - } - } else { + // Create dedicated background display items per-frame when we're + // handling events. + // XXX how to handle collapsed borders? + if (aBuilder->IsForEventDelivery()) { nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, aFrame->GetRectRelativeToSelf(), - aLists.BorderBackground()); + lists->BorderBackground()); } // Paint the inset box-shadows for the table frames if (hasBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( + lists->BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame)); } } - aTraversal(aBuilder, aFrame, aDirtyRect, aLists); - - if (aFrame->IsVisibleForPainting(aBuilder)) { - if (aFrame->IsTableFrame()) { - nsTableFrame* table = static_cast<nsTableFrame*>(aFrame); - // In the collapsed border model, overlay all collapsed borders. - if (table->IsBorderCollapse()) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table)); - } else { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBorder(aBuilder, table)); - } - } + aTraversal(aBuilder, aFrame, aDirtyRect, *lists); + + if (sortEventBackgrounds) { + // Ensure that the table frame event background goes before the + // table rowgroups event backgrounds, before the table row event backgrounds, + // before everything else (cells and their blocks) + separatedCollection.BorderBackground()->Sort<nsDisplayItem*>(TablePartRankComparator()); + separatedCollection.MoveTo(aLists); } aFrame->DisplayOutline(aBuilder, aLists); } static inline bool FrameHasBorderOrBackground(nsTableFrame* tableFrame, nsIFrame* f) { if (!f->StyleVisibility()->IsVisible()) { @@ -1488,26 +1399,91 @@ static inline bool FrameHasBorderOrBackg if (cellFrame && !tableFrame->IsBorderCollapse()) { return false; } return true; } return false; } +static bool +AnyTablePartHasBorderOrBackground(nsTableFrame* aTableFrame, + nsIFrame* aStart, + nsIFrame* aEnd) +{ + for (nsIFrame* f = aStart; f != aEnd; f = f->GetNextSibling()) { + NS_ASSERTION(IsFrameAllowedInTable(f->Type()), "unexpected frame type"); + + if (FrameHasBorderOrBackground(aTableFrame, f)) + return true; + + nsTableCellFrame *cellFrame = do_QueryFrame(f); + if (cellFrame) + continue; + + if (AnyTablePartHasBorderOrBackground(aTableFrame, + f->PrincipalChildList().FirstChild(), + nullptr)) + return true; + } + + return false; +} + +static void +UpdateItemForColGroupBackgrounds(nsDisplayTableItem* item, + const nsFrameList& aFrames) { + for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) { + nsTableColGroupFrame* cg = static_cast<nsTableColGroupFrame*>(e.get()); + item->UpdateForFrameBackground(cg); + for (nsTableColFrame* colFrame = cg->GetFirstColumn(); colFrame; + colFrame = colFrame->GetNextCol()) { + item->UpdateForFrameBackground(colFrame); + } + } +} + // table paint code is concerned primarily with borders and bg color // SEC: TODO: adjust the rect for captions void nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255)); - DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); + nsDisplayTableItem* item = nullptr; + if (IsVisibleInSelection(aBuilder)) { + nsMargin deflate = GetDeflationForBackground(PresContext()); + if (StyleVisibility()->IsVisible()) { + // If 'deflate' is (0,0,0,0) then we can paint the table background + // in its own display item, so do that to take advantage of + // opacity and visibility optimizations + if (deflate == nsMargin(0, 0, 0, 0)) { + DisplayBackgroundUnconditional(aBuilder, aLists, false); + } + } + + // This background is created if any of the table parts are visible, + // or if we're doing event handling (since DisplayGenericTablePart + // needs the item for the |sortEventBackgrounds|-dependent code). + // Specific visibility decisions are delegated to the table background + // painter, which handles borders and backgrounds for the table. + if (aBuilder->IsForEventDelivery() || + AnyTablePartHasBorderOrBackground(this, this, GetNextSibling()) || + AnyTablePartHasBorderOrBackground(this, mColGroups.FirstChild(), nullptr)) { + item = new (aBuilder) nsDisplayTableBorderBackground(aBuilder, this, + deflate != nsMargin(0, 0, 0, 0)); + aLists.BorderBackground()->AppendNewToTop(item); + } + } + DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); + if (item) { + UpdateItemForColGroupBackgrounds(item, mColGroups); + } } nsMargin nsTableFrame::GetDeflationForBackground(nsPresContext* aPresContext) const { if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode() || !IsBorderCollapse()) return nsMargin(0,0,0,0);
--- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -240,16 +240,17 @@ public: * @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 nsRect& aDirtyRect, const nsDisplayListSet& aLists, + nsDisplayTableItem* aDisplayItem, DisplayGenericTablePartTraversal aTraversal = GenericTraversal); // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. static nsIFrame* GetFrameAtOrBefore(nsIFrame* aParentFrame, nsIFrame* aPriorChildFrame, mozilla::LayoutFrameType aChildType); bool IsAutoBSize(mozilla::WritingMode aWM);
--- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -616,17 +616,31 @@ nsDisplayTableRowBackground::Paint(nsDis nsDisplayTableItemGeometry::UpdateDrawResult(this, result); } void nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); + nsDisplayTableItem* item = nullptr; + if (IsVisibleInSelection(aBuilder)) { + bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); + if (isRoot) { + // This background is created regardless of whether this frame is + // visible or not. Visibility decisions are delegated to the + // table background painter. + // We would use nsDisplayGeneric for this rare case except that we + // need the background to be larger than the row frame in some + // cases. + item = new (aBuilder) nsDisplayTableRowBackground(aBuilder, this); + aLists.BorderBackground()->AppendNewToTop(item); + } + } + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); } nsIFrame::LogicalSides nsTableRowFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const { if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone)) { return LogicalSides();
--- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -288,18 +288,29 @@ DisplayRows(nsDisplayListBuilder* aBuild } } void nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { + nsDisplayTableItem* item = nullptr; + if (IsVisibleInSelection(aBuilder)) { + bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); + if (isRoot) { + // This background is created regardless of whether this frame is + // visible or not. Visibility decisions are delegated to the + // table background painter. + item = new (aBuilder) nsDisplayTableRowGroupBackground(aBuilder, this); + aLists.BorderBackground()->AppendNewToTop(item); + } + } nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, - aLists, DisplayRows); + aLists, item, DisplayRows); } nsIFrame::LogicalSides nsTableRowGroupFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const { if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone)) { return LogicalSides();
--- a/layout/tables/nsTableWrapperFrame.cpp +++ b/layout/tables/nsTableWrapperFrame.cpp @@ -185,21 +185,17 @@ nsTableWrapperFrame::BuildDisplayList(ns BuildDisplayListForInnerTable(aBuilder, aDirtyRect, set); nsDisplayListSet captionSet(set, set.BlockBorderBackgrounds()); BuildDisplayListForChild(aBuilder, mCaptionFrames.FirstChild(), aDirtyRect, captionSet); // Now we have to sort everything by content order, since the caption // may be somewhere inside the table - set.BlockBorderBackgrounds()->SortByContentOrder(GetContent()); - set.Floats()->SortByContentOrder(GetContent()); - set.Content()->SortByContentOrder(GetContent()); - set.PositionedDescendants()->SortByContentOrder(GetContent()); - set.Outlines()->SortByContentOrder(GetContent()); + set.SortAllByContentOrder(GetContent()); set.MoveTo(aLists); } void nsTableWrapperFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) {