1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsTableCellFrame.h"
9 #include "gfxContext.h"
11 #include "mozilla/ComputedStyle.h"
12 #include "mozilla/PresShell.h"
13 #include "mozilla/ScrollContainerFrame.h"
14 #include "mozilla/StaticPrefs_layout.h"
15 #include "mozilla/gfx/2D.h"
16 #include "mozilla/gfx/Helpers.h"
17 #include "nsTableFrame.h"
18 #include "nsTableColFrame.h"
19 #include "nsTableRowFrame.h"
20 #include "nsTableRowGroupFrame.h"
21 #include "nsStyleConsts.h"
22 #include "nsPresContext.h"
23 #include "nsCSSRendering.h"
24 #include "nsIContent.h"
26 #include "nsIFrameInlines.h"
27 #include "nsGenericHTMLElement.h"
28 #include "nsAttrValueInlines.h"
29 #include "nsHTMLParts.h"
30 #include "nsGkAtoms.h"
31 #include "nsDisplayList.h"
32 #include "nsLayoutUtils.h"
33 #include "nsTextFrame.h"
36 // TABLECELL SELECTION
37 #include "nsFrameSelection.h"
38 #include "mozilla/LookAndFeel.h"
41 # include "nsAccessibilityService.h"
44 using namespace mozilla
;
45 using namespace mozilla::gfx
;
46 using namespace mozilla::image
;
48 nsTableCellFrame::nsTableCellFrame(ComputedStyle
* aStyle
,
49 nsTableFrame
* aTableFrame
, ClassID aID
)
50 : nsContainerFrame(aStyle
, aTableFrame
->PresContext(), aID
),
51 mDesiredSize(aTableFrame
->GetWritingMode()) {
52 SetContentEmpty(false);
55 nsTableCellFrame::~nsTableCellFrame() = default;
57 NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame
)
59 void nsTableCellFrame::Init(nsIContent
* aContent
, nsContainerFrame
* aParent
,
60 nsIFrame
* aPrevInFlow
) {
61 // Let the base class do its initialization
62 nsContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
64 if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER
)) {
65 AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT
);
69 // Set the column index
70 nsTableCellFrame
* cellFrame
= (nsTableCellFrame
*)aPrevInFlow
;
71 uint32_t colIndex
= cellFrame
->ColIndex();
72 SetColIndex(colIndex
);
74 // Although the spec doesn't say that writing-mode is not applied to
75 // table-cells, we still override style value here because we want to
76 // make effective writing mode of table structure frames consistent
77 // within a table. The content inside table cells is reflowed by an
78 // anonymous block, hence their writing mode is not affected.
79 mWritingMode
= GetTableFrame()->GetWritingMode();
83 void nsTableCellFrame::Destroy(DestroyContext
& aContext
) {
84 nsTableFrame::MaybeUnregisterPositionedTablePart(this);
85 nsContainerFrame::Destroy(aContext
);
88 // nsIPercentBSizeObserver methods
90 void nsTableCellFrame::NotifyPercentBSize(const ReflowInput
& aReflowInput
) {
91 // ReflowInput ensures the mCBReflowInput of blocks inside a
92 // cell is the cell frame, not the inner-cell block, and that the
93 // containing block of an inner table is the containing block of its
95 // XXXldb Given the now-stricter |NeedsToObserve|, many if not all of
96 // these tests are probably unnecessary.
98 // Maybe the cell reflow input; we sure if we're inside the |if|.
99 const ReflowInput
* cellRI
= aReflowInput
.mCBReflowInput
;
101 if (cellRI
&& cellRI
->mFrame
== this &&
102 (cellRI
->ComputedBSize() == NS_UNCONSTRAINEDSIZE
||
103 cellRI
->ComputedBSize() == 0)) { // XXXldb Why 0?
104 // This is a percentage bsize on a frame whose percentage bsizes
105 // are based on the bsize of the cell, since its containing block
106 // is the inner cell frame.
108 // We'll only honor the percent bsize if sibling-cells/ancestors
109 // have specified/pct bsize. (Also, siblings only count for this if
110 // both this cell and the sibling cell span exactly 1 row.)
112 if (nsTableFrame::AncestorsHaveStyleBSize(*cellRI
) ||
113 (GetTableFrame()->GetEffectiveRowSpan(*this) == 1 &&
114 cellRI
->mParentReflowInput
->mFrame
->HasAnyStateBits(
115 NS_ROW_HAS_CELL_WITH_STYLE_BSIZE
))) {
116 for (const ReflowInput
* rs
= aReflowInput
.mParentReflowInput
;
117 rs
!= cellRI
; rs
= rs
->mParentReflowInput
) {
118 rs
->mFrame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE
);
121 nsTableFrame::RequestSpecialBSizeReflow(*cellRI
);
126 // The cell needs to observe its block and things inside its block but nothing
128 bool nsTableCellFrame::NeedsToObserve(const ReflowInput
& aReflowInput
) {
129 const ReflowInput
* rs
= aReflowInput
.mParentReflowInput
;
133 if (rs
->mFrame
== this) {
134 // We always observe the child block. It will never send any
135 // notifications, but we need this so that the observer gets
136 // propagated to its kids.
139 rs
= rs
->mParentReflowInput
;
144 // We always need to let the percent bsize observer be propagated
145 // from a table wrapper frame to an inner table frame.
146 LayoutFrameType fType
= aReflowInput
.mFrame
->Type();
147 if (fType
== LayoutFrameType::Table
) {
151 // We need the observer to be propagated to all children of the cell
152 // (i.e., children of the child block) in quirks mode, but only to
153 // tables in standards mode.
154 // XXX This may not be true in the case of orthogonal flows within
155 // the cell (bug 1174711 comment 8); we may need to observe isizes
156 // instead of bsizes for orthogonal children.
157 return rs
->mFrame
== this &&
158 (PresContext()->CompatibilityMode() == eCompatibility_NavQuirks
||
159 fType
== LayoutFrameType::TableWrapper
);
162 nsresult
nsTableCellFrame::AttributeChanged(int32_t aNameSpaceID
,
165 // We need to recalculate in this case because of the nowrap quirk in
166 // BasicTableLayoutStrategy
167 if (aNameSpaceID
== kNameSpaceID_None
&& aAttribute
== nsGkAtoms::nowrap
&&
168 PresContext()->CompatibilityMode() == eCompatibility_NavQuirks
) {
169 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors
,
173 const nsAtom
* colSpanAttribute
=
174 MOZ_UNLIKELY(mContent
->AsElement()->IsMathMLElement())
175 ? nsGkAtoms::columnspan_
176 : nsGkAtoms::colspan
;
177 if (aAttribute
== nsGkAtoms::rowspan
|| aAttribute
== colSpanAttribute
) {
178 nsLayoutUtils::PostRestyleEvent(mContent
->AsElement(), RestyleHint
{0},
179 nsChangeHint_UpdateTableCellSpans
);
185 void nsTableCellFrame::DidSetComputedStyle(ComputedStyle
* aOldComputedStyle
) {
186 nsContainerFrame::DidSetComputedStyle(aOldComputedStyle
);
187 nsTableFrame::PositionedTablePartMaybeChanged(this, aOldComputedStyle
);
189 if (!aOldComputedStyle
) {
190 return; // avoid the following on init
194 if (nsAccessibilityService
* accService
= GetAccService()) {
195 if (StyleBorder()->GetComputedBorder() !=
196 aOldComputedStyle
->StyleBorder()->GetComputedBorder()) {
197 // If a table cell's computed border changes, it can change whether or
198 // not its parent table is classified as a layout or data table. We
199 // send a notification here to invalidate the a11y cache on the table
200 // so the next fetch of IsProbablyLayoutTable() is accurate.
201 accService
->TableLayoutGuessMaybeChanged(PresShell(), mContent
);
206 nsTableFrame
* tableFrame
= GetTableFrame();
207 if (tableFrame
->IsBorderCollapse() &&
208 tableFrame
->BCRecalcNeeded(aOldComputedStyle
, Style())) {
209 uint32_t colIndex
= ColIndex();
210 uint32_t rowIndex
= RowIndex();
211 // row span needs to be clamped as we do not create rows in the cellmap
212 // which do not have cells originating in them
213 TableArea
damageArea(colIndex
, rowIndex
, GetColSpan(),
214 std::min(static_cast<uint32_t>(GetRowSpan()),
215 tableFrame
->GetRowCount() - rowIndex
));
216 tableFrame
->AddBCDamageArea(damageArea
);
221 void nsTableCellFrame::AppendFrames(ChildListID aListID
,
222 nsFrameList
&& aFrameList
) {
223 MOZ_CRASH("unsupported operation");
226 void nsTableCellFrame::InsertFrames(ChildListID aListID
, nsIFrame
* aPrevFrame
,
227 const nsLineList::iterator
* aPrevFrameLine
,
228 nsFrameList
&& aFrameList
) {
229 MOZ_CRASH("unsupported operation");
232 void nsTableCellFrame::RemoveFrame(DestroyContext
&, ChildListID
, nsIFrame
*) {
233 MOZ_CRASH("unsupported operation");
237 void nsTableCellFrame::SetColIndex(int32_t aColIndex
) { mColIndex
= aColIndex
; }
240 nsMargin
nsTableCellFrame::GetUsedMargin() const {
241 return nsMargin(0, 0, 0, 0);
244 // ASSURE DIFFERENT COLORS for selection
245 inline nscolor
EnsureDifferentColors(nscolor colorA
, nscolor colorB
) {
246 if (colorA
== colorB
) {
248 res
= NS_RGB(NS_GET_R(colorA
) ^ 0xff, NS_GET_G(colorA
) ^ 0xff,
249 NS_GET_B(colorA
) ^ 0xff);
255 void nsTableCellFrame::DecorateForSelection(DrawTarget
* aDrawTarget
,
257 NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
258 int16_t displaySelection
;
259 displaySelection
= DetermineDisplaySelection();
260 if (displaySelection
) {
261 RefPtr
<nsFrameSelection
> frameSelection
= PresShell()->FrameSelection();
263 if (frameSelection
->IsInTableSelectionMode()) {
265 if (displaySelection
== nsISelectionController::SELECTION_DISABLED
) {
266 bordercolor
= NS_RGB(176, 176, 176); // disabled color
268 bordercolor
= LookAndFeel::Color(LookAndFeel::ColorID::Highlight
, this);
270 nscoord threePx
= nsPresContext::CSSPixelsToAppUnits(3);
271 if ((mRect
.width
> threePx
) && (mRect
.height
> threePx
)) {
272 // compare bordercolor to background-color
273 bordercolor
= EnsureDifferentColors(
274 bordercolor
, StyleBackground()->BackgroundColor(this));
276 int32_t appUnitsPerDevPixel
= PresContext()->AppUnitsPerDevPixel();
277 Point devPixelOffset
= NSPointToPoint(aPt
, appUnitsPerDevPixel
);
279 AutoRestoreTransform
autoRestoreTransform(aDrawTarget
);
280 aDrawTarget
->SetTransform(
281 aDrawTarget
->GetTransform().PreTranslate(devPixelOffset
));
283 ColorPattern
color(ToDeviceColor(bordercolor
));
285 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
287 StrokeLineWithSnapping(nsPoint(onePixel
, 0), nsPoint(mRect
.width
, 0),
288 appUnitsPerDevPixel
, *aDrawTarget
, color
);
289 StrokeLineWithSnapping(nsPoint(0, onePixel
), nsPoint(0, mRect
.height
),
290 appUnitsPerDevPixel
, *aDrawTarget
, color
);
291 StrokeLineWithSnapping(nsPoint(onePixel
, mRect
.height
),
292 nsPoint(mRect
.width
, mRect
.height
),
293 appUnitsPerDevPixel
, *aDrawTarget
, color
);
294 StrokeLineWithSnapping(nsPoint(mRect
.width
, onePixel
),
295 nsPoint(mRect
.width
, mRect
.height
),
296 appUnitsPerDevPixel
, *aDrawTarget
, color
);
298 nsRect
r(onePixel
, onePixel
, mRect
.width
- onePixel
,
299 mRect
.height
- onePixel
);
301 NSRectToSnappedRect(r
, appUnitsPerDevPixel
, *aDrawTarget
);
302 aDrawTarget
->StrokeRect(devPixelRect
, color
);
304 StrokeLineWithSnapping(
305 nsPoint(2 * onePixel
, mRect
.height
- 2 * onePixel
),
306 nsPoint(mRect
.width
- onePixel
, mRect
.height
- (2 * onePixel
)),
307 appUnitsPerDevPixel
, *aDrawTarget
, color
);
308 StrokeLineWithSnapping(
309 nsPoint(mRect
.width
- (2 * onePixel
), 2 * onePixel
),
310 nsPoint(mRect
.width
- (2 * onePixel
), mRect
.height
- onePixel
),
311 appUnitsPerDevPixel
, *aDrawTarget
, color
);
317 void nsTableCellFrame::ProcessBorders(nsTableFrame
* aFrame
,
318 nsDisplayListBuilder
* aBuilder
,
319 const nsDisplayListSet
& aLists
) {
320 const nsStyleBorder
* borderStyle
= StyleBorder();
321 if (aFrame
->IsBorderCollapse() || !borderStyle
->HasBorder()) {
325 if (!GetContentEmpty() ||
326 StyleTableBorder()->mEmptyCells
== StyleEmptyCells::Show
) {
327 aLists
.BorderBackground()->AppendNewToTop
<nsDisplayBorder
>(aBuilder
, this);
331 void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey
,
332 bool aRebuildDisplayItems
) {
333 nsIFrame::InvalidateFrame(aDisplayItemKey
, aRebuildDisplayItems
);
334 if (GetTableFrame()->IsBorderCollapse()) {
335 const bool rebuild
= StaticPrefs::layout_display_list_retain_sc();
336 GetParent()->InvalidateFrameWithRect(InkOverflowRect() + GetPosition(),
337 aDisplayItemKey
, rebuild
);
341 void nsTableCellFrame::InvalidateFrameWithRect(const nsRect
& aRect
,
342 uint32_t aDisplayItemKey
,
343 bool aRebuildDisplayItems
) {
344 nsIFrame::InvalidateFrameWithRect(aRect
, aDisplayItemKey
,
345 aRebuildDisplayItems
);
346 // If we have filters applied that would affects our bounds, then
347 // we get an inactive layer created and this is computed
348 // within FrameLayerBuilder
349 GetParent()->InvalidateFrameWithRect(aRect
+ GetPosition(), aDisplayItemKey
,
350 aRebuildDisplayItems
);
353 bool nsTableCellFrame::ShouldPaintBordersAndBackgrounds() const {
354 // If we're not visible, we don't paint.
355 if (!StyleVisibility()->IsVisible()) {
359 // Consider 'empty-cells', but only in separated borders mode.
360 if (!GetContentEmpty()) {
364 nsTableFrame
* tableFrame
= GetTableFrame();
365 if (tableFrame
->IsBorderCollapse()) {
369 return StyleTableBorder()->mEmptyCells
== StyleEmptyCells::Show
;
372 bool nsTableCellFrame::ShouldPaintBackground(nsDisplayListBuilder
* aBuilder
) {
373 return ShouldPaintBordersAndBackgrounds();
376 LogicalSides
nsTableCellFrame::GetLogicalSkipSides() const {
377 LogicalSides
skip(mWritingMode
);
378 if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak
==
379 StyleBoxDecorationBreak::Clone
)) {
383 if (GetPrevInFlow()) {
384 skip
+= LogicalSide::BStart
;
386 if (GetNextInFlow()) {
387 skip
+= LogicalSide::BEnd
;
393 nsMargin
nsTableCellFrame::GetBorderOverflow() { return nsMargin(0, 0, 0, 0); }
395 void nsTableCellFrame::BlockDirAlignChild(
396 WritingMode aWM
, nscoord aMaxAscent
,
397 ForceAlignTopForTableCell aForceAlignTop
) {
398 MOZ_ASSERT(aForceAlignTop
!= ForceAlignTopForTableCell::Yes
||
399 PresContext()->IsPaginated(),
400 "We shouldn't force table-cells to do 'vertical-align:top' if "
401 "we're not in printing!");
403 /* It's the 'border-collapse' on the table that matters */
404 const LogicalMargin border
= GetLogicalUsedBorder(GetWritingMode())
405 .ApplySkipSides(GetLogicalSkipSides())
406 .ConvertTo(aWM
, GetWritingMode());
408 nscoord bStartInset
= border
.BStart(aWM
);
409 nscoord bEndInset
= border
.BEnd(aWM
);
411 nscoord bSize
= BSize(aWM
);
412 nsIFrame
* inner
= Inner();
413 nsSize containerSize
= mRect
.Size();
414 LogicalRect kidRect
= inner
->GetLogicalRect(aWM
, containerSize
);
415 nscoord childBSize
= kidRect
.BSize(aWM
);
417 // Vertically align the child
418 const auto verticalAlign
= aForceAlignTop
== ForceAlignTopForTableCell::Yes
419 ? StyleVerticalAlignKeyword::Top
420 : GetVerticalAlign();
421 nscoord kidBStart
= 0;
422 switch (verticalAlign
) {
423 case StyleVerticalAlignKeyword::Baseline
:
424 if (!GetContentEmpty()) {
425 // Align the baselines of the child frame with the baselines of
426 // other children in the same row which have 'vertical-align: baseline'
427 kidBStart
= bStartInset
+ aMaxAscent
- GetCellBaseline();
430 // Empty cells don't participate in baseline alignment -
431 // fallback to start alignment.
433 case StyleVerticalAlignKeyword::Top
:
434 // Align the top of the child frame with the top of the content area,
435 kidBStart
= bStartInset
;
438 case StyleVerticalAlignKeyword::Bottom
:
439 // Align the bottom of the child frame with the bottom of the content
441 kidBStart
= bSize
- childBSize
- bEndInset
;
445 case StyleVerticalAlignKeyword::Middle
:
446 // Align the middle of the child frame with the middle of the content
448 kidBStart
= (bSize
- childBSize
- bEndInset
+ bStartInset
) / 2;
450 // If the content is larger than the cell bsize, align from bStartInset
451 // (cell's content-box bstart edge).
452 kidBStart
= std::max(bStartInset
, kidBStart
);
454 if (kidBStart
!= kidRect
.BStart(aWM
)) {
455 // Invalidate at the old position first
456 inner
->InvalidateFrameSubtree();
459 inner
->SetPosition(aWM
, LogicalPoint(aWM
, kidRect
.IStart(aWM
), kidBStart
),
461 ReflowOutput
desiredSize(aWM
);
462 desiredSize
.SetSize(aWM
, GetLogicalSize(aWM
));
464 nsRect
overflow(nsPoint(), GetSize());
465 overflow
.Inflate(GetBorderOverflow());
466 desiredSize
.mOverflowAreas
.SetAllTo(overflow
);
467 ConsiderChildOverflow(desiredSize
.mOverflowAreas
, inner
);
468 FinishAndStoreOverflow(&desiredSize
);
469 if (kidBStart
!= kidRect
.BStart(aWM
)) {
470 // Make sure any child views are correctly positioned. We know the inner
471 // table cell won't have a view
472 nsContainerFrame::PositionChildViews(inner
);
474 // Invalidate new overflow rect
475 inner
->InvalidateFrameSubtree();
478 nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(),
479 desiredSize
.InkOverflow(),
480 ReflowChildFlags::Default
);
484 bool nsTableCellFrame::ComputeCustomOverflow(OverflowAreas
& aOverflowAreas
) {
485 nsRect
bounds(nsPoint(0, 0), GetSize());
486 bounds
.Inflate(GetBorderOverflow());
488 aOverflowAreas
.UnionAllWith(bounds
);
489 return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas
);
492 // Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom',
493 // length, percentage, and calc() values to 'baseline'.
494 StyleVerticalAlignKeyword
nsTableCellFrame::GetVerticalAlign() const {
495 const StyleVerticalAlign
& verticalAlign
= StyleDisplay()->mVerticalAlign
;
496 if (verticalAlign
.IsKeyword()) {
497 auto value
= verticalAlign
.AsKeyword();
498 if (value
== StyleVerticalAlignKeyword::Top
||
499 value
== StyleVerticalAlignKeyword::Middle
||
500 value
== StyleVerticalAlignKeyword::Bottom
) {
504 return StyleVerticalAlignKeyword::Baseline
;
507 static bool CellHasVisibleContent(nsTableFrame
* aTableFrame
,
508 nsTableCellFrame
* aCell
) {
509 // see http://www.w3.org/TR/CSS21/tables.html#empty-cells
510 nsIFrame
* content
= aCell
->CellContentFrame();
511 if (content
->GetContentRect().Height() > 0) {
514 if (aTableFrame
->IsBorderCollapse()) {
517 for (nsIFrame
* innerFrame
: content
->PrincipalChildList()) {
518 LayoutFrameType frameType
= innerFrame
->Type();
519 if (LayoutFrameType::Text
== frameType
) {
520 nsTextFrame
* textFrame
= static_cast<nsTextFrame
*>(innerFrame
);
521 if (textFrame
->HasNoncollapsedCharacters()) {
524 } else if (LayoutFrameType::Placeholder
!= frameType
) {
526 } else if (nsLayoutUtils::GetFloatFromPlaceholder(innerFrame
)) {
533 nsIFrame
* nsTableCellFrame::Inner() const {
534 MOZ_ASSERT(mFrames
.OnlyChild(),
535 "A table cell should have exactly one child!");
536 return mFrames
.FirstChild();
539 nsIFrame
* nsTableCellFrame::CellContentFrame() const {
540 nsIFrame
* inner
= Inner();
541 if (ScrollContainerFrame
* sf
= do_QueryFrame(inner
)) {
542 return sf
->GetScrolledFrame();
547 nscoord
nsTableCellFrame::GetCellBaseline() const {
548 // Ignore the position of the inner frame relative to the cell frame
549 // since we want the position as though the inner were top-aligned.
550 const auto wm
= GetWritingMode();
552 if (!StyleDisplay()->IsContainLayout() &&
553 nsLayoutUtils::GetFirstLineBaseline(wm
, Inner(), &result
)) {
554 // `result` already includes the padding-start from the inner frame.
555 return result
+ GetLogicalUsedBorder(wm
).BStart(wm
);
557 return CellContentFrame()->ContentBSize(wm
) +
558 GetLogicalUsedBorderAndPadding(wm
).BStart(wm
);
561 int32_t nsTableCellFrame::GetRowSpan() {
564 // Don't look at the content's rowspan if we're a pseudo cell
565 if (!Style()->IsPseudoOrAnonBox()) {
566 dom::Element
* elem
= mContent
->AsElement();
567 const nsAttrValue
* attr
= elem
->GetParsedAttr(nsGkAtoms::rowspan
);
568 // Note that we don't need to check the tag name, because only table cells
569 // (including MathML <mtd>) and table headers parse the "rowspan" attribute
571 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
572 rowSpan
= attr
->GetIntegerValue();
578 int32_t nsTableCellFrame::GetColSpan() {
581 // Don't look at the content's colspan if we're a pseudo cell
582 if (!Style()->IsPseudoOrAnonBox()) {
583 dom::Element
* elem
= mContent
->AsElement();
584 const nsAttrValue
* attr
= elem
->GetParsedAttr(
585 MOZ_UNLIKELY(elem
->IsMathMLElement()) ? nsGkAtoms::columnspan_
586 : nsGkAtoms::colspan
);
587 // Note that we don't need to check the tag name, because only table cells
588 // (including MathML <mtd>) and table headers parse the "colspan" attribute
590 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
591 colSpan
= attr
->GetIntegerValue();
597 ScrollContainerFrame
* nsTableCellFrame::GetScrollTargetFrame() const {
598 return do_QueryFrame(Inner());
601 nscoord
nsTableCellFrame::IntrinsicISize(const IntrinsicSizeInput
& aInput
,
602 IntrinsicISizeType aType
) {
603 // Note: a table cell has the same writing mode as its table ancestor, which
604 // may differ from its inner frame that derives its writing mode from the
605 // style of the <td> element. See nsTableCellFrame::Init().
606 const IntrinsicSizeInput
innerInput(aInput
, Inner()->GetWritingMode(),
608 return nsLayoutUtils::IntrinsicForContainer(
609 innerInput
.mContext
, Inner(), aType
,
610 innerInput
.mPercentageBasisForChildren
, nsLayoutUtils::IGNORE_PADDING
);
613 /* virtual */ nsIFrame::IntrinsicSizeOffsetData
614 nsTableCellFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis
) {
615 IntrinsicSizeOffsetData result
=
616 nsContainerFrame::IntrinsicISizeOffsets(aPercentageBasis
);
620 WritingMode wm
= GetWritingMode();
621 result
.border
= GetBorderWidth(wm
).IStartEnd(wm
);
627 # define PROBABLY_TOO_LARGE 1000000
628 static void DebugCheckChildSize(nsIFrame
* aChild
, ReflowOutput
& aMet
) {
629 WritingMode wm
= aMet
.GetWritingMode();
630 if ((aMet
.ISize(wm
) < 0) || (aMet
.ISize(wm
) > PROBABLY_TOO_LARGE
)) {
631 printf("WARNING: cell content %p has large inline size %d \n",
632 static_cast<void*>(aChild
), int32_t(aMet
.ISize(wm
)));
637 // the computed bsize for the cell, which descendants use for percent bsize
638 // calculations it is the bsize (minus border, padding) of the cell's first in
639 // flow during its final reflow without an unconstrained bsize.
640 static nscoord
CalcUnpaginatedBSize(nsTableCellFrame
& aCellFrame
,
641 nsTableFrame
& aTableFrame
,
642 nscoord aBlockDirBorderPadding
) {
643 const nsTableCellFrame
* firstCellInFlow
=
644 static_cast<nsTableCellFrame
*>(aCellFrame
.FirstInFlow());
645 nsTableFrame
* firstTableInFlow
=
646 static_cast<nsTableFrame
*>(aTableFrame
.FirstInFlow());
647 nsTableRowFrame
* row
=
648 static_cast<nsTableRowFrame
*>(firstCellInFlow
->GetParent());
649 nsTableRowGroupFrame
* firstRGInFlow
=
650 static_cast<nsTableRowGroupFrame
*>(row
->GetParent());
652 uint32_t rowIndex
= firstCellInFlow
->RowIndex();
653 int32_t rowSpan
= aTableFrame
.GetEffectiveRowSpan(*firstCellInFlow
);
655 nscoord computedBSize
=
656 firstTableInFlow
->GetRowSpacing(rowIndex
, rowIndex
+ rowSpan
- 1);
657 computedBSize
-= aBlockDirBorderPadding
;
659 for (row
= firstRGInFlow
->GetFirstRow(), rowX
= 0; row
;
660 row
= row
->GetNextRow(), rowX
++) {
661 if (rowX
> rowIndex
+ rowSpan
- 1) {
663 } else if (rowX
>= rowIndex
) {
664 computedBSize
+= row
->GetUnpaginatedBSize();
667 return computedBSize
;
670 void nsTableCellFrame::Reflow(nsPresContext
* aPresContext
,
671 ReflowOutput
& aDesiredSize
,
672 const ReflowInput
& aReflowInput
,
673 nsReflowStatus
& aStatus
) {
675 DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
676 MOZ_ASSERT(aStatus
.IsEmpty(), "Caller should pass a fresh reflow status!");
678 if (aReflowInput
.mFlags
.mSpecialBSizeReflow
) {
679 FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW
);
682 // see if a special bsize reflow needs to occur due to having a pct height
683 nsTableFrame::CheckRequestSpecialBSizeReflow(aReflowInput
);
685 WritingMode wm
= aReflowInput
.GetWritingMode();
686 LogicalSize availSize
= aReflowInput
.AvailableSize();
688 // @note |this| frame applies borders but not any padding. Our anonymous
689 // inner frame applies the padding (but not borders).
690 LogicalMargin border
= GetBorderWidth(wm
);
692 ReflowOutput
kidSize(wm
);
693 SetPriorAvailISize(aReflowInput
.AvailableISize());
694 nsIFrame
* inner
= Inner();
695 nsTableFrame
* tableFrame
= GetTableFrame();
697 if (aReflowInput
.mFlags
.mSpecialBSizeReflow
|| aPresContext
->IsPaginated()) {
698 // Here, we're changing our own reflow input, so we need to account for our
699 // padding, even though we don't apply it anywhere else, to get the correct
700 // percentage resolution on children.
701 const LogicalMargin bp
= border
+ aReflowInput
.ComputedLogicalPadding(wm
);
702 if (aReflowInput
.mFlags
.mSpecialBSizeReflow
) {
703 const_cast<ReflowInput
&>(aReflowInput
)
704 .SetComputedBSize(BSize(wm
) - bp
.BStartEnd(wm
));
706 const nscoord computedUnpaginatedBSize
=
707 CalcUnpaginatedBSize(*this, *tableFrame
, bp
.BStartEnd(wm
));
708 if (computedUnpaginatedBSize
> 0) {
709 const_cast<ReflowInput
&>(aReflowInput
)
710 .SetComputedBSize(computedUnpaginatedBSize
);
715 // We need to apply the skip sides for current fragmentainer's border after
716 // we finish calculating the special block-size or unpaginated block-size to
717 // prevent the skip sides from affecting the results.
719 // We assume we are the last fragment by using
720 // PreReflowBlockLevelLogicalSkipSides(), i.e. the block-end border and
721 // padding is not skipped.
722 border
.ApplySkipSides(PreReflowBlockLevelLogicalSkipSides());
724 availSize
.ISize(wm
) -= border
.IStartEnd(wm
);
726 // If we have a constrained available block-size, shrink it by subtracting our
727 // block-direction border and padding for our children.
728 if (NS_UNCONSTRAINEDSIZE
!= availSize
.BSize(wm
)) {
729 availSize
.BSize(wm
) -= border
.BStart(wm
);
731 if (aReflowInput
.mStyleBorder
->mBoxDecorationBreak
==
732 StyleBoxDecorationBreak::Clone
) {
733 // We have box-decoration-break:clone. Subtract block-end border from the
734 // available block-size as well.
735 availSize
.BSize(wm
) -= border
.BEnd(wm
);
739 // Available block-size can became negative after subtracting block-direction
740 // border and padding. Per spec, to guarantee progress, fragmentainers are
741 // assumed to have a minimum block size of 1px regardless of their used size.
742 // https://drafts.csswg.org/css-break/#breaking-rules
743 availSize
.BSize(wm
) =
744 std::max(availSize
.BSize(wm
), nsPresContext::CSSPixelsToAppUnits(1));
746 WritingMode kidWM
= inner
->GetWritingMode();
747 ReflowInput
kidReflowInput(aPresContext
, aReflowInput
, inner
,
748 availSize
.ConvertTo(kidWM
, wm
), Nothing(),
749 ReflowInput::InitFlag::CallerWillInit
);
750 // Override computed padding, in case it's percentage padding
752 const auto padding
= aReflowInput
.ComputedLogicalPadding(kidWM
);
753 kidReflowInput
.Init(aPresContext
, Nothing(), Nothing(), Some(padding
));
754 if (inner
->IsScrollContainerFrame()) {
755 // Propagate explicit block sizes to our inner frame, if it's a scroll
756 // frame. Note that in table layout, explicit heights act as a minimum
757 // height, see nsTableRowFrame::CalcCellActualBSize.
759 // Table cells don't respect box-sizing, so we need to remove the
760 // padding, so that the scroll-frame sizes properly (since the
761 // scrollbars also add to the padding area).
762 auto ToScrolledBSize
= [&](const nscoord aBSize
) {
763 return std::max(0, aBSize
- padding
.BStartEnd(kidWM
));
765 nscoord minBSize
= aReflowInput
.ComputedMinBSize();
766 if (aReflowInput
.ComputedBSize() != NS_UNCONSTRAINEDSIZE
) {
767 minBSize
= std::max(minBSize
, aReflowInput
.ComputedBSize());
770 kidReflowInput
.SetComputedMinBSize(ToScrolledBSize(minBSize
));
775 // Don't be a percent height observer if we're in the middle of
776 // special-bsize reflow, in case we get an accidental NotifyPercentBSize()
777 // call (which we shouldn't honor during special-bsize reflow)
778 if (!aReflowInput
.mFlags
.mSpecialBSizeReflow
) {
779 // mPercentBSizeObserver is for children of cells in quirks mode,
780 // but only those than are tables in standards mode. NeedsToObserve
781 // will determine how far this is propagated to descendants.
782 kidReflowInput
.mPercentBSizeObserver
= this;
784 // Don't propagate special bsize reflow input to our kids
785 kidReflowInput
.mFlags
.mSpecialBSizeReflow
= false;
787 if (aReflowInput
.mFlags
.mSpecialBSizeReflow
||
788 FirstInFlow()->HasAnyStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW
)) {
789 // We need to force the kid to have mBResize set if we've had a
790 // special reflow in the past, since the non-special reflow needs to
791 // resize back to what it was without the special bsize reflow.
792 kidReflowInput
.SetBResize(true);
795 nsSize containerSize
= aReflowInput
.ComputedSizeAsContainerIfConstrained();
797 const LogicalPoint kidOrigin
= border
.StartOffset(wm
);
798 const nsRect origRect
= inner
->GetRect();
799 const nsRect origInkOverflow
= inner
->InkOverflowRect();
800 const bool firstReflow
= inner
->HasAnyStateBits(NS_FRAME_FIRST_REFLOW
);
802 ReflowChild(inner
, aPresContext
, kidSize
, kidReflowInput
, wm
, kidOrigin
,
803 containerSize
, ReflowChildFlags::Default
, aStatus
);
804 if (aStatus
.IsOverflowIncomplete()) {
805 // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually
807 // XXX should paginate overflow as overflow, but not in this patch (bug
809 aStatus
.SetIncomplete();
810 NS_WARNING(nsPrintfCString("Set table cell incomplete %p", this).get());
813 // XXXbz is this invalidate actually needed, really?
814 if (HasAnyStateBits(NS_FRAME_IS_DIRTY
)) {
815 InvalidateFrameSubtree();
819 DebugCheckChildSize(inner
, kidSize
);
823 FinishReflowChild(inner
, aPresContext
, kidSize
, &kidReflowInput
, wm
,
824 kidOrigin
, containerSize
, ReflowChildFlags::Default
);
827 nsIFrame
* prevInFlow
= GetPrevInFlow();
830 ? static_cast<nsTableCellFrame
*>(prevInFlow
)->GetContentEmpty()
831 : !CellHasVisibleContent(tableFrame
, this);
832 SetContentEmpty(isEmpty
);
835 if (tableFrame
->IsBorderCollapse()) {
836 nsTableFrame::InvalidateTableFrame(inner
, origRect
, origInkOverflow
,
839 // first, compute the bsize which can be set w/o being restricted by
841 LogicalSize
cellSize(wm
);
842 cellSize
.BSize(wm
) = kidSize
.BSize(wm
);
844 if (NS_UNCONSTRAINEDSIZE
!= cellSize
.BSize(wm
)) {
845 cellSize
.BSize(wm
) += border
.BStart(wm
);
847 if (aStatus
.IsComplete() ||
848 aReflowInput
.mStyleBorder
->mBoxDecorationBreak
==
849 StyleBoxDecorationBreak::Clone
) {
850 cellSize
.BSize(wm
) += border
.BEnd(wm
);
854 // next determine the cell's isize. At this point, we've factored in the
855 // cell's style attributes.
856 cellSize
.ISize(wm
) = kidSize
.ISize(wm
);
858 // factor in border (and disregard padding, which is handled by our child).
859 if (NS_UNCONSTRAINEDSIZE
!= cellSize
.ISize(wm
)) {
860 cellSize
.ISize(wm
) += border
.IStartEnd(wm
);
863 // set the cell's desired size and max element size
864 aDesiredSize
.SetSize(wm
, cellSize
);
866 // the overflow area will be computed when BlockDirAlignChild() gets called
868 if (aReflowInput
.mFlags
.mSpecialBSizeReflow
&&
869 NS_UNCONSTRAINEDSIZE
== aReflowInput
.AvailableBSize()) {
870 aDesiredSize
.BSize(wm
) = BSize(wm
);
873 // If our parent is in initial reflow, it'll handle invalidating our
874 // entire overflow rect.
875 if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW
) &&
876 nsSize(aDesiredSize
.Width(), aDesiredSize
.Height()) != mRect
.Size()) {
880 // remember the desired size for this reflow
881 SetDesiredSize(aDesiredSize
);
883 // Any absolutely-positioned children will get reflowed in
884 // nsIFrame::FixupPositionedTableParts in another pass, so propagate our
885 // dirtiness to them before our parent clears our dirty bits.
886 PushDirtyBitToAbsoluteFrames();
889 void nsBCTableCellFrame::Reflow(nsPresContext
* aPresContext
,
890 ReflowOutput
& aDesiredSize
,
891 const ReflowInput
& aReflowInput
,
892 nsReflowStatus
& aStatus
) {
893 nsTableCellFrame::Reflow(aPresContext
, aDesiredSize
, aReflowInput
, aStatus
);
894 mLastUsedBorder
= GetUsedBorder();
897 /* ----- global methods ----- */
899 NS_QUERYFRAME_HEAD(nsTableCellFrame
)
900 NS_QUERYFRAME_ENTRY(nsTableCellFrame
)
901 NS_QUERYFRAME_ENTRY(nsITableCellLayout
)
902 NS_QUERYFRAME_ENTRY(nsIPercentBSizeObserver
)
903 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
906 a11y::AccType
nsTableCellFrame::AccessibleType() {
907 return a11y::eHTMLTableCellType
;
911 /* This is primarily for editor access via nsITableLayout */
913 nsTableCellFrame::GetCellIndexes(int32_t& aRowIndex
, int32_t& aColIndex
) {
914 aRowIndex
= RowIndex();
915 aColIndex
= mColIndex
;
919 nsTableCellFrame
* NS_NewTableCellFrame(PresShell
* aPresShell
,
920 ComputedStyle
* aStyle
,
921 nsTableFrame
* aTableFrame
) {
922 if (aTableFrame
->IsBorderCollapse()) {
923 return new (aPresShell
) nsBCTableCellFrame(aStyle
, aTableFrame
);
925 return new (aPresShell
) nsTableCellFrame(aStyle
, aTableFrame
);
928 NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame
)
930 LogicalMargin
nsTableCellFrame::GetBorderWidth(WritingMode aWM
) const {
931 return LogicalMargin(aWM
, StyleBorder()->GetComputedBorder());
934 void nsTableCellFrame::AppendDirectlyOwnedAnonBoxes(
935 nsTArray
<OwnedAnonBox
>& aResult
) {
936 aResult
.AppendElement(OwnedAnonBox(Inner()));
939 #ifdef DEBUG_FRAME_DUMP
940 nsresult
nsTableCellFrame::GetFrameName(nsAString
& aResult
) const {
941 return MakeFrameName(u
"TableCell"_ns
, aResult
);
945 // nsBCTableCellFrame
947 nsBCTableCellFrame::nsBCTableCellFrame(ComputedStyle
* aStyle
,
948 nsTableFrame
* aTableFrame
)
949 : nsTableCellFrame(aStyle
, aTableFrame
, kClassID
) {}
951 nsBCTableCellFrame::~nsBCTableCellFrame() = default;
954 nsMargin
nsBCTableCellFrame::GetUsedBorder() const {
955 WritingMode wm
= GetWritingMode();
956 return GetBorderWidth(wm
).GetPhysicalMargin(wm
);
959 #ifdef DEBUG_FRAME_DUMP
960 nsresult
nsBCTableCellFrame::GetFrameName(nsAString
& aResult
) const {
961 return MakeFrameName(u
"BCTableCell"_ns
, aResult
);
965 LogicalMargin
nsBCTableCellFrame::GetBorderWidth(WritingMode aWM
) const {
966 return LogicalMargin(
967 aWM
, BC_BORDER_END_HALF(mBStartBorder
), BC_BORDER_START_HALF(mIEndBorder
),
968 BC_BORDER_START_HALF(mBEndBorder
), BC_BORDER_END_HALF(mIStartBorder
));
971 nscoord
nsBCTableCellFrame::GetBorderWidth(LogicalSide aSide
) const {
973 case LogicalSide::BStart
:
974 return BC_BORDER_END_HALF(mBStartBorder
);
975 case LogicalSide::IEnd
:
976 return BC_BORDER_START_HALF(mIEndBorder
);
977 case LogicalSide::BEnd
:
978 return BC_BORDER_START_HALF(mBEndBorder
);
980 return BC_BORDER_END_HALF(mIStartBorder
);
984 void nsBCTableCellFrame::SetBorderWidth(LogicalSide aSide
, nscoord aValue
) {
986 case LogicalSide::BStart
:
987 mBStartBorder
= aValue
;
989 case LogicalSide::IEnd
:
990 mIEndBorder
= aValue
;
992 case LogicalSide::BEnd
:
993 mBEndBorder
= aValue
;
996 mIStartBorder
= aValue
;
1001 nsMargin
nsBCTableCellFrame::GetBorderOverflow() {
1002 WritingMode wm
= GetWritingMode();
1003 LogicalMargin
halfBorder(
1004 wm
, BC_BORDER_START_HALF(mBStartBorder
), BC_BORDER_END_HALF(mIEndBorder
),
1005 BC_BORDER_END_HALF(mBEndBorder
), BC_BORDER_START_HALF(mIStartBorder
));
1006 return halfBorder
.GetPhysicalMargin(wm
);
1011 class nsDisplayTableCellSelection final
: public nsPaintedDisplayItem
{
1013 nsDisplayTableCellSelection(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
)
1014 : nsPaintedDisplayItem(aBuilder
, aFrame
) {
1015 MOZ_COUNT_CTOR(nsDisplayTableCellSelection
);
1017 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayTableCellSelection
)
1019 void Paint(nsDisplayListBuilder
* aBuilder
, gfxContext
* aCtx
) override
{
1020 static_cast<nsTableCellFrame
*>(mFrame
)->DecorateForSelection(
1021 aCtx
->GetDrawTarget(), ToReferenceFrame());
1023 NS_DISPLAY_DECL_NAME("TableCellSelection", TYPE_TABLE_CELL_SELECTION
)
1025 bool CreateWebRenderCommands(
1026 mozilla::wr::DisplayListBuilder
& aBuilder
,
1027 mozilla::wr::IpcResourceUpdateQueue
& aResources
,
1028 const StackingContextHelper
& aSc
,
1029 mozilla::layers::RenderRootStateManager
* aManager
,
1030 nsDisplayListBuilder
* aDisplayListBuilder
) override
{
1031 RefPtr
<nsFrameSelection
> frameSelection
=
1032 mFrame
->PresShell()->FrameSelection();
1033 return !frameSelection
->IsInTableSelectionMode();
1037 } // namespace mozilla
1039 void nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
1040 const nsDisplayListSet
& aLists
) {
1041 DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
1042 if (ShouldPaintBordersAndBackgrounds()) {
1043 // display outset box-shadows if we need to.
1044 bool hasBoxShadow
= !StyleEffects()->mBoxShadow
.IsEmpty();
1046 aLists
.BorderBackground()->AppendNewToTop
<nsDisplayBoxShadowOuter
>(
1050 nsRect bgRect
= GetRectRelativeToSelf() + aBuilder
->ToReferenceFrame(this);
1051 nsRect bgRectInsideBorder
= bgRect
;
1053 // If we're doing collapsed borders, and this element forms a new stacking
1054 // context or has position:relative (which paints as though it did), inset
1055 // the background rect so that we don't overpaint the inset part of our
1057 nsTableFrame
* tableFrame
= GetTableFrame();
1058 if (tableFrame
->IsBorderCollapse() &&
1059 (IsStackingContext() ||
1060 StyleDisplay()->mPosition
== StylePositionProperty::Relative
)) {
1061 bgRectInsideBorder
.Deflate(GetUsedBorder());
1064 // display background if we need to.
1065 const AppendedBackgroundType result
=
1066 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
1067 aBuilder
, this, bgRectInsideBorder
, aLists
.BorderBackground(), true,
1069 if (result
== AppendedBackgroundType::None
) {
1070 aBuilder
->BuildCompositorHitTestInfoIfNeeded(this,
1071 aLists
.BorderBackground());
1074 // display inset box-shadows if we need to.
1076 aLists
.BorderBackground()->AppendNewToTop
<nsDisplayBoxShadowInner
>(
1080 // display borders if we need to
1081 ProcessBorders(tableFrame
, aBuilder
, aLists
);
1083 // and display the selection border if we need to
1085 aLists
.BorderBackground()->AppendNewToTop
<nsDisplayTableCellSelection
>(
1089 // This can be null if display list building initiated in the middle
1090 // of the table, which can happen with background-clip:text and
1092 nsDisplayTableBackgroundSet
* backgrounds
=
1093 aBuilder
->GetTableBackgroundSet();
1095 // Compute bgRect relative to reference frame, but using the
1096 // normal (without position:relative offsets) positions for the
1097 // cell, row and row group.
1098 bgRect
= GetRectRelativeToSelf() + GetNormalPosition();
1100 nsTableRowFrame
* row
= GetTableRowFrame();
1101 bgRect
+= row
->GetNormalPosition();
1103 nsTableRowGroupFrame
* rowGroup
= row
->GetTableRowGroupFrame();
1104 bgRect
+= rowGroup
->GetNormalPosition();
1106 bgRect
+= backgrounds
->TableToReferenceFrame();
1108 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
1109 nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter
asrSetter(
1111 if (IsStackingContext() || row
->IsStackingContext() ||
1112 rowGroup
->IsStackingContext() || tableFrame
->IsStackingContext()) {
1113 // The col/colgroup items we create below will be inserted directly into
1114 // the BorderBackgrounds list of the table frame. That means that
1115 // they'll be moved *outside* of any wrapper items created for any
1116 // frames between this table cell frame and the table wrapper frame, and
1117 // will not participate in those frames's opacity / transform / filter /
1118 // mask effects. If one of those frames is a stacking context, then we
1119 // may have one or more of those wrapper items, and one of them may have
1120 // captured a clip. In order to ensure correct clipping and scrolling of
1121 // the col/colgroup items, restore the clip and ASR that we observed
1122 // when we entered the table frame. If that frame is a stacking context
1123 // but doesn't have any clip capturing wrapper items, then we'll
1124 // double-apply the clip. That's ok.
1125 clipState
.SetClipChainForContainingBlockDescendants(
1126 backgrounds
->GetTableClipChain());
1127 asrSetter
.SetCurrentActiveScrolledRoot(backgrounds
->GetTableASR());
1130 // Create backgrounds items as needed for the column and column
1131 // group that this cell occupies.
1132 nsTableColFrame
* col
= backgrounds
->GetColForIndex(ColIndex());
1133 nsTableColGroupFrame
* colGroup
= col
->GetTableColGroupFrame();
1135 Maybe
<nsDisplayListBuilder::AutoBuildingDisplayList
> buildingForColGroup
;
1136 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
1137 aBuilder
, colGroup
, bgRect
, backgrounds
->ColGroupBackgrounds(), false,
1138 colGroup
->GetRect() + backgrounds
->TableToReferenceFrame(), this,
1139 &buildingForColGroup
);
1141 Maybe
<nsDisplayListBuilder::AutoBuildingDisplayList
> buildingForCol
;
1142 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
1143 aBuilder
, col
, bgRect
, backgrounds
->ColBackgrounds(), false,
1144 col
->GetRect() + colGroup
->GetPosition() +
1145 backgrounds
->TableToReferenceFrame(),
1146 this, &buildingForCol
);
1150 // the 'empty-cells' property has no effect on 'outline'
1151 DisplayOutline(aBuilder
, aLists
);
1153 // The child's background will go in our BorderBackground() list.
1154 // This isn't a problem since it won't have a real background except for
1155 // event handling. We do not call BuildDisplayListForNonBlockChildren
1156 // because that/ would put the child's background in the Content() list
1157 // which isn't right (e.g., would end up on top of our child floats for
1159 BuildDisplayListForChild(aBuilder
, Inner(), aLists
);