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/. */
5 #include "nsTableRowFrame.h"
6 #include "nsTableRowGroupFrame.h"
7 #include "nsIPresShell.h"
8 #include "nsPresContext.h"
9 #include "nsStyleContext.h"
10 #include "nsStyleConsts.h"
11 #include "nsGkAtoms.h"
12 #include "nsIContent.h"
13 #include "nsTableFrame.h"
14 #include "nsTableCellFrame.h"
15 #include "nsCSSRendering.h"
16 #include "nsHTMLParts.h"
17 #include "nsTableColGroupFrame.h"
18 #include "nsTableColFrame.h"
20 #include "nsDisplayList.h"
21 #include "nsIFrameInlines.h"
24 using namespace mozilla
;
26 struct nsTableCellReflowState
: public nsHTMLReflowState
28 nsTableCellReflowState(nsPresContext
* aPresContext
,
29 const nsHTMLReflowState
& aParentReflowState
,
31 const LogicalSize
& aAvailableSpace
,
33 : nsHTMLReflowState(aPresContext
, aParentReflowState
, aFrame
,
34 aAvailableSpace
, -1, -1, aFlags
)
38 void FixUp(const nsSize
& aAvailSpace
);
41 void nsTableCellReflowState::FixUp(const nsSize
& aAvailSpace
)
43 // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
44 NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE
!= aAvailSpace
.width
,
45 "have unconstrained width; this should only result from "
46 "very large sizes, not attempts at intrinsic width "
48 if (NS_UNCONSTRAINEDSIZE
!= ComputedWidth()) {
49 nscoord computedWidth
=
50 aAvailSpace
.width
- mComputedBorderPadding
.LeftRight();
51 computedWidth
= std::max(0, computedWidth
);
52 SetComputedWidth(computedWidth
);
54 if (NS_UNCONSTRAINEDSIZE
!= ComputedHeight() &&
55 NS_UNCONSTRAINEDSIZE
!= aAvailSpace
.height
) {
56 nscoord computedHeight
=
57 aAvailSpace
.height
- mComputedBorderPadding
.TopBottom();
58 computedHeight
= std::max(0, computedHeight
);
59 SetComputedHeight(computedHeight
);
64 nsTableRowFrame::InitChildReflowState(nsPresContext
& aPresContext
,
65 const nsSize
& aAvailSize
,
67 nsTableCellReflowState
& aReflowState
)
69 nsMargin collapseBorder
;
70 nsMargin
* pCollapseBorder
= nullptr;
71 if (aBorderCollapse
) {
72 // we only reflow cells, so don't need to check frame type
73 nsBCTableCellFrame
* bcCellFrame
= (nsBCTableCellFrame
*)aReflowState
.frame
;
75 pCollapseBorder
= bcCellFrame
->GetBorderWidth(collapseBorder
);
78 aReflowState
.Init(&aPresContext
, -1, -1, pCollapseBorder
);
79 aReflowState
.FixUp(aAvailSize
);
83 nsTableRowFrame::SetFixedHeight(nscoord aValue
)
85 nscoord height
= std::max(0, aValue
);
86 if (HasFixedHeight()) {
87 if (height
> mStyleFixedHeight
) {
88 mStyleFixedHeight
= height
;
92 mStyleFixedHeight
= height
;
94 SetHasFixedHeight(true);
100 nsTableRowFrame::SetPctHeight(float aPctValue
,
103 nscoord height
= std::max(0, NSToCoordRound(aPctValue
* 100.0f
));
104 if (HasPctHeight()) {
105 if ((height
> mStylePctHeight
) || aForce
) {
106 mStylePctHeight
= height
;
110 mStylePctHeight
= height
;
112 SetHasPctHeight(true);
117 /* ----------- nsTableRowFrame ---------- */
119 NS_QUERYFRAME_HEAD(nsTableRowFrame
)
120 NS_QUERYFRAME_ENTRY(nsTableRowFrame
)
121 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
123 nsTableRowFrame::nsTableRowFrame(nsStyleContext
* aContext
)
124 : nsContainerFrame(aContext
)
126 mBits
.mRowIndex
= mBits
.mFirstInserted
= 0;
130 nsTableRowFrame::~nsTableRowFrame()
135 nsTableRowFrame::Init(nsIContent
* aContent
,
136 nsContainerFrame
* aParent
,
137 nsIFrame
* aPrevInFlow
)
139 // Let the base class do its initialization
140 nsContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
142 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
== StyleDisplay()->mDisplay
,
143 "wrong display on table row frame");
147 nsTableRowFrame
* rowFrame
= (nsTableRowFrame
*)aPrevInFlow
;
149 SetRowIndex(rowFrame
->GetRowIndex());
154 nsTableRowFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
156 if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
) {
157 nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot
);
160 nsContainerFrame::DestroyFrom(aDestructRoot
);
164 nsTableRowFrame::DidSetStyleContext(nsStyleContext
* aOldStyleContext
)
166 nsContainerFrame::DidSetStyleContext(aOldStyleContext
);
168 if (!aOldStyleContext
) //avoid this on init
171 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
172 if (tableFrame
->IsBorderCollapse() &&
173 tableFrame
->BCRecalcNeeded(aOldStyleContext
, StyleContext())) {
174 nsIntRect
damageArea(0, GetRowIndex(), tableFrame
->GetColCount(), 1);
175 tableFrame
->AddBCDamageArea(damageArea
);
180 nsTableRowFrame::AppendFrames(ChildListID aListID
,
181 nsFrameList
& aFrameList
)
183 NS_ASSERTION(aListID
== kPrincipalList
, "unexpected child list");
185 DrainSelfOverflowList(); // ensure the last frame is in mFrames
186 const nsFrameList::Slice
& newCells
= mFrames
.AppendFrames(nullptr, aFrameList
);
188 // Add the new cell frames to the table
189 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
190 for (nsFrameList::Enumerator
e(newCells
) ; !e
.AtEnd(); e
.Next()) {
191 nsIFrame
*childFrame
= e
.get();
192 NS_ASSERTION(IS_TABLE_CELL(childFrame
->GetType()),"Not a table cell frame/pseudo frame construction failure");
193 tableFrame
->AppendCell(static_cast<nsTableCellFrame
&>(*childFrame
), GetRowIndex());
196 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
197 NS_FRAME_HAS_DIRTY_CHILDREN
);
198 tableFrame
->SetGeometryDirty();
203 nsTableRowFrame::InsertFrames(ChildListID aListID
,
204 nsIFrame
* aPrevFrame
,
205 nsFrameList
& aFrameList
)
207 NS_ASSERTION(aListID
== kPrincipalList
, "unexpected child list");
208 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
209 "inserting after sibling frame with different parent");
210 DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames
211 //Insert Frames in the frame list
212 const nsFrameList::Slice
& newCells
= mFrames
.InsertFrames(nullptr, aPrevFrame
, aFrameList
);
214 // Get the table frame
215 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
216 nsIAtom
* cellFrameType
= tableFrame
->IsBorderCollapse() ? nsGkAtoms::bcTableCellFrame
: nsGkAtoms::tableCellFrame
;
217 nsTableCellFrame
* prevCellFrame
= (nsTableCellFrame
*)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
, cellFrameType
);
218 nsTArray
<nsTableCellFrame
*> cellChildren
;
219 for (nsFrameList::Enumerator
e(newCells
); !e
.AtEnd(); e
.Next()) {
220 nsIFrame
*childFrame
= e
.get();
221 NS_ASSERTION(IS_TABLE_CELL(childFrame
->GetType()),"Not a table cell frame/pseudo frame construction failure");
222 cellChildren
.AppendElement(static_cast<nsTableCellFrame
*>(childFrame
));
224 // insert the cells into the cell map
225 int32_t colIndex
= -1;
227 prevCellFrame
->GetColIndex(colIndex
);
229 tableFrame
->InsertCells(cellChildren
, GetRowIndex(), colIndex
);
231 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
232 NS_FRAME_HAS_DIRTY_CHILDREN
);
233 tableFrame
->SetGeometryDirty();
237 nsTableRowFrame::RemoveFrame(ChildListID aListID
,
240 NS_ASSERTION(aListID
== kPrincipalList
, "unexpected child list");
242 MOZ_ASSERT((nsTableCellFrame
*)do_QueryFrame(aOldFrame
));
243 nsTableCellFrame
* cellFrame
= static_cast<nsTableCellFrame
*>(aOldFrame
);
244 // remove the cell from the cell map
245 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
246 tableFrame
->RemoveCell(cellFrame
, GetRowIndex());
248 // Remove the frame and destroy it
249 mFrames
.DestroyFrame(aOldFrame
);
251 PresContext()->PresShell()->
252 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
253 NS_FRAME_HAS_DIRTY_CHILDREN
);
255 tableFrame
->SetGeometryDirty();
258 /* virtual */ nsMargin
259 nsTableRowFrame::GetUsedMargin() const
261 return nsMargin(0,0,0,0);
264 /* virtual */ nsMargin
265 nsTableRowFrame::GetUsedBorder() const
267 return nsMargin(0,0,0,0);
270 /* virtual */ nsMargin
271 nsTableRowFrame::GetUsedPadding() const
273 return nsMargin(0,0,0,0);
277 GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame
& aTableCellFrame
,
278 nsTableFrame
& aTableFrame
)
281 int32_t rowSpan
= aTableFrame
.GetEffectiveRowSpan(aTableCellFrame
);
282 // add in height of rows spanned beyond the 1st one
283 nsIFrame
* nextRow
= aTableCellFrame
.GetParent()->GetNextSibling();
284 for (int32_t rowX
= 1; ((rowX
< rowSpan
) && nextRow
);) {
285 if (nsGkAtoms::tableRowFrame
== nextRow
->GetType()) {
286 height
+= nextRow
->GetSize().height
;
289 height
+= aTableFrame
.GetCellSpacingY(rowX
);
290 nextRow
= nextRow
->GetNextSibling();
296 nsTableRowFrame::GetFirstCell()
298 nsIFrame
* childFrame
= mFrames
.FirstChild();
300 nsTableCellFrame
*cellFrame
= do_QueryFrame(childFrame
);
304 childFrame
= childFrame
->GetNextSibling();
310 * Post-reflow hook. This is where the table row does its post-processing
313 nsTableRowFrame::DidResize()
315 // Resize and re-align the cell frames based on our row height
316 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
317 nsTableIterator
iter(*this);
318 nsIFrame
* childFrame
= iter
.First();
320 WritingMode wm
= GetWritingMode();
321 nsHTMLReflowMetrics
desiredSize(wm
);
322 desiredSize
.SetSize(wm
, GetLogicalSize(wm
));
323 desiredSize
.SetOverflowAreasToDesiredBounds();
326 nsTableCellFrame
*cellFrame
= do_QueryFrame(childFrame
);
328 nscoord cellHeight
= mRect
.height
+ GetHeightOfRowsSpannedBelowFirst(*cellFrame
, *tableFrame
);
330 // resize the cell's height
331 nsRect cellRect
= cellFrame
->GetRect();
332 nsRect cellVisualOverflow
= cellFrame
->GetVisualOverflowRect();
333 if (cellRect
.height
!= cellHeight
)
335 cellFrame
->SetSize(nsSize(cellRect
.width
, cellHeight
));
336 nsTableFrame::InvalidateTableFrame(cellFrame
, cellRect
,
341 // realign cell content based on the new height. We might be able to
342 // skip this if the height didn't change... maybe. Hard to tell.
343 cellFrame
->VerticallyAlignChild(mMaxCellAscent
);
345 // Always store the overflow, even if the height didn't change, since
346 // we'll lose part of our overflow area otherwise.
347 ConsiderChildOverflow(desiredSize
.mOverflowAreas
, cellFrame
);
349 // Note that if the cell's *content* needs to change in response
350 // to this height, it will get a special height reflow.
352 // Get the next child
353 childFrame
= iter
.Next();
355 FinishAndStoreOverflow(&desiredSize
);
357 nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(),
358 desiredSize
.VisualOverflow(), 0);
360 // Let our base class do the usual work
363 // returns max-ascent amongst all cells that have 'vertical-align: baseline'
364 // *including* cells with rowspans
365 nscoord
nsTableRowFrame::GetMaxCellAscent() const
367 return mMaxCellAscent
;
370 nscoord
nsTableRowFrame::GetRowBaseline(WritingMode aWritingMode
)
373 return mMaxCellAscent
;
375 // If we don't have a baseline on any of the cells we go for the lowest
376 // content edge of the inner block frames.
377 // Every table cell has a cell frame with its border and padding. Inside
378 // the cell is a block frame. The cell is as high as the tallest cell in
379 // the parent row. As a consequence the block frame might not touch both
380 // the top and the bottom padding of it parent cell frame at the same time.
382 // bbbbbbbbbbbbbbbbbb cell border: b
383 // bppppppppppppppppb cell padding: p
384 // bpxxxxxxxxxxxxxxpb inner block: x
388 // bpxxxxxxxxxxxxxxpb base line
391 // bppppppppppppppppb
392 // bbbbbbbbbbbbbbbbbb
394 nsTableIterator
iter(*this);
395 nsIFrame
* childFrame
= iter
.First();
398 if (IS_TABLE_CELL(childFrame
->GetType())) {
399 nsIFrame
* firstKid
= childFrame
->GetFirstPrincipalChild();
400 ascent
= std::max(ascent
, firstKid
->GetRect().YMost());
402 // Get the next child
403 childFrame
= iter
.Next();
408 nsTableRowFrame::GetHeight(nscoord aPctBasis
) const
411 if ((aPctBasis
> 0) && HasPctHeight()) {
412 height
= NSToCoordRound(GetPctHeight() * (float)aPctBasis
);
414 if (HasFixedHeight()) {
415 height
= std::max(height
, GetFixedHeight());
417 return std::max(height
, GetContentHeight());
421 nsTableRowFrame::ResetHeight(nscoord aFixedHeight
)
423 SetHasFixedHeight(false);
424 SetHasPctHeight(false);
429 if (aFixedHeight
> 0) {
430 SetFixedHeight(aFixedHeight
);
438 nsTableRowFrame::UpdateHeight(nscoord aHeight
,
441 nsTableFrame
* aTableFrame
,
442 nsTableCellFrame
* aCellFrame
)
444 if (!aTableFrame
|| !aCellFrame
) {
445 NS_ASSERTION(false , "invalid call");
449 if (aHeight
!= NS_UNCONSTRAINEDSIZE
) {
450 if (!(aCellFrame
->HasVerticalAlignBaseline())) { // only the cell's height matters
451 if (GetHeight() < aHeight
) {
452 int32_t rowSpan
= aTableFrame
->GetEffectiveRowSpan(*aCellFrame
);
454 SetContentHeight(aHeight
);
458 else { // the alignment on the baseline can change the height
459 NS_ASSERTION((aAscent
!= NS_UNCONSTRAINEDSIZE
) && (aDescent
!= NS_UNCONSTRAINEDSIZE
), "invalid call");
460 // see if this is a long ascender
461 if (mMaxCellAscent
< aAscent
) {
462 mMaxCellAscent
= aAscent
;
464 // see if this is a long descender and without rowspan
465 if (mMaxCellDescent
< aDescent
) {
466 int32_t rowSpan
= aTableFrame
->GetEffectiveRowSpan(*aCellFrame
);
468 mMaxCellDescent
= aDescent
;
471 // keep the tallest height in sync
472 if (GetHeight() < mMaxCellAscent
+ mMaxCellDescent
) {
473 SetContentHeight(mMaxCellAscent
+ mMaxCellDescent
);
480 nsTableRowFrame::CalcHeight(const nsHTMLReflowState
& aReflowState
)
482 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
483 nscoord computedHeight
= (NS_UNCONSTRAINEDSIZE
== aReflowState
.ComputedHeight())
484 ? 0 : aReflowState
.ComputedHeight();
485 ResetHeight(computedHeight
);
487 const nsStylePosition
* position
= StylePosition();
488 if (position
->mHeight
.ConvertsToLength()) {
489 SetFixedHeight(nsRuleNode::ComputeCoordPercentCalc(position
->mHeight
, 0));
491 else if (eStyleUnit_Percent
== position
->mHeight
.GetUnit()) {
492 SetPctHeight(position
->mHeight
.GetPercentValue());
494 // calc() with percentages is treated like 'auto' on table rows.
496 for (nsIFrame
* kidFrame
= mFrames
.FirstChild(); kidFrame
;
497 kidFrame
= kidFrame
->GetNextSibling()) {
498 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
500 WritingMode wm
= cellFrame
->GetWritingMode();
501 LogicalSize desSize
= cellFrame
->GetDesiredSize();
502 if ((NS_UNCONSTRAINEDSIZE
== aReflowState
.AvailableHeight()) && !GetPrevInFlow()) {
503 CalculateCellActualHeight(cellFrame
, desSize
.BSize(wm
));
505 // height may have changed, adjust descent to absorb any excess difference
507 if (!kidFrame
->GetFirstPrincipalChild()->GetFirstPrincipalChild())
508 ascent
= desSize
.BSize(wm
);
510 ascent
= cellFrame
->GetCellBaseline();
511 nscoord descent
= desSize
.BSize(wm
) - ascent
;
512 UpdateHeight(desSize
.BSize(wm
), ascent
, descent
, tableFrame
, cellFrame
);
519 * We need a custom display item for table row backgrounds. This is only used
520 * when the table row is the root of a stacking context (e.g., has 'opacity').
521 * Table row backgrounds can extend beyond the row frame bounds, when
522 * the row contains row-spanning cells.
524 class nsDisplayTableRowBackground
: public nsDisplayTableItem
{
526 nsDisplayTableRowBackground(nsDisplayListBuilder
* aBuilder
,
527 nsTableRowFrame
* aFrame
) :
528 nsDisplayTableItem(aBuilder
, aFrame
) {
529 MOZ_COUNT_CTOR(nsDisplayTableRowBackground
);
531 #ifdef NS_BUILD_REFCNT_LOGGING
532 virtual ~nsDisplayTableRowBackground() {
533 MOZ_COUNT_DTOR(nsDisplayTableRowBackground
);
537 virtual void ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
538 const nsDisplayItemGeometry
* aGeometry
,
539 nsRegion
*aInvalidRegion
) MOZ_OVERRIDE
;
540 virtual void Paint(nsDisplayListBuilder
* aBuilder
,
541 nsRenderingContext
* aCtx
) MOZ_OVERRIDE
;
542 NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND
)
546 nsDisplayTableRowBackground::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
547 const nsDisplayItemGeometry
* aGeometry
,
548 nsRegion
*aInvalidRegion
)
550 if (aBuilder
->ShouldSyncDecodeImages()) {
551 if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame
, mFrame
->GetNextSibling())) {
553 aInvalidRegion
->Or(*aInvalidRegion
, GetBounds(aBuilder
, &snap
));
557 nsDisplayTableItem::ComputeInvalidationRegion(aBuilder
, aGeometry
, aInvalidRegion
);
561 nsDisplayTableRowBackground::Paint(nsDisplayListBuilder
* aBuilder
,
562 nsRenderingContext
* aCtx
)
564 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(mFrame
);
565 TableBackgroundPainter
painter(tableFrame
,
566 TableBackgroundPainter::eOrigin_TableRow
,
567 mFrame
->PresContext(), *aCtx
,
568 mVisibleRect
, ToReferenceFrame(),
569 aBuilder
->GetBackgroundPaintFlags());
570 painter
.PaintRow(static_cast<nsTableRowFrame
*>(mFrame
));
574 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
575 const nsRect
& aDirtyRect
,
576 const nsDisplayListSet
& aLists
)
578 nsDisplayTableItem
* item
= nullptr;
579 if (IsVisibleInSelection(aBuilder
)) {
580 bool isRoot
= aBuilder
->IsAtRootOfPseudoStackingContext();
582 // This background is created regardless of whether this frame is
583 // visible or not. Visibility decisions are delegated to the
584 // table background painter.
585 // We would use nsDisplayGeneric for this rare case except that we
586 // need the background to be larger than the row frame in some
588 item
= new (aBuilder
) nsDisplayTableRowBackground(aBuilder
, this);
589 aLists
.BorderBackground()->AppendNewToTop(item
);
592 nsTableFrame::DisplayGenericTablePart(aBuilder
, this, aDirtyRect
, aLists
, item
);
595 nsIFrame::LogicalSides
596 nsTableRowFrame::GetLogicalSkipSides(const nsHTMLReflowState
* aReflowState
) const
598 if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak
==
599 NS_STYLE_BOX_DECORATION_BREAK_CLONE
)) {
600 return LogicalSides();
604 if (nullptr != GetPrevInFlow()) {
605 skip
|= eLogicalSideBitsBStart
;
607 if (nullptr != GetNextInFlow()) {
608 skip
|= eLogicalSideBitsBEnd
;
613 // Calculate the cell's actual height given its pass2 height.
614 // Takes into account the specified height (in the style).
615 // Modifies the desired height that is passed in.
617 nsTableRowFrame::CalculateCellActualHeight(nsTableCellFrame
* aCellFrame
,
618 nscoord
& aDesiredHeight
)
620 nscoord specifiedHeight
= 0;
622 // Get the height specified in the style information
623 const nsStylePosition
* position
= aCellFrame
->StylePosition();
625 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
626 int32_t rowSpan
= tableFrame
->GetEffectiveRowSpan(*aCellFrame
);
628 switch (position
->mHeight
.GetUnit()) {
629 case eStyleUnit_Calc
: {
630 if (position
->mHeight
.CalcHasPercent()) {
631 // Treat this like "auto"
634 // Fall through to the coord case
636 case eStyleUnit_Coord
: {
637 nscoord outsideBoxSizing
= 0;
638 // In quirks mode, table cell width should be content-box, but height
639 // should be border-box.
640 // Because of this historic anomaly, we do not use quirk.css
641 // (since we can't specify one value of box-sizing for width and another
643 if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks
) {
644 switch (position
->mBoxSizing
) {
645 case NS_STYLE_BOX_SIZING_CONTENT
:
646 outsideBoxSizing
= aCellFrame
->GetUsedBorderAndPadding().TopBottom();
648 case NS_STYLE_BOX_SIZING_PADDING
:
649 outsideBoxSizing
= aCellFrame
->GetUsedBorder().TopBottom();
652 // NS_STYLE_BOX_SIZING_BORDER
658 nsRuleNode::ComputeCoordPercentCalc(position
->mHeight
, 0) +
662 SetFixedHeight(specifiedHeight
);
665 case eStyleUnit_Percent
: {
667 SetPctHeight(position
->mHeight
.GetPercentValue());
668 // pct heights are handled when all of the cells are finished, so don't set specifiedHeight
671 case eStyleUnit_Auto
:
676 // If the specified height is greater than the desired height, then use the specified height
677 if (specifiedHeight
> aDesiredHeight
)
678 aDesiredHeight
= specifiedHeight
;
683 // Calculates the available width for the table cell based on the known
684 // column widths taking into account column spans and column spacing
686 CalcAvailWidth(nsTableFrame
& aTableFrame
,
687 nsTableCellFrame
& aCellFrame
)
689 nscoord cellAvailWidth
= 0;
691 aCellFrame
.GetColIndex(colIndex
);
692 int32_t colspan
= aTableFrame
.GetEffectiveColSpan(aCellFrame
);
693 NS_ASSERTION(colspan
> 0, "effective colspan should be positive");
695 for (int32_t spanX
= 0; spanX
< colspan
; spanX
++) {
696 cellAvailWidth
+= aTableFrame
.GetColumnWidth(colIndex
+ spanX
);
698 aTableFrame
.ColumnHasCellSpacingBefore(colIndex
+ spanX
)) {
699 cellAvailWidth
+= aTableFrame
.GetCellSpacingX(colIndex
+ spanX
- 1);
702 return cellAvailWidth
;
706 GetSpaceBetween(int32_t aPrevColIndex
,
709 nsTableFrame
& aTableFrame
,
711 bool aCheckVisibility
)
715 if (aIsLeftToRight
) {
716 for (colX
= aPrevColIndex
+ 1; aColIndex
> colX
; colX
++) {
717 bool isCollapsed
= false;
718 if (!aCheckVisibility
) {
719 space
+= aTableFrame
.GetColumnWidth(colX
);
722 nsTableColFrame
* colFrame
= aTableFrame
.GetColFrame(colX
);
723 const nsStyleVisibility
* colVis
= colFrame
->StyleVisibility();
724 bool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
== colVis
->mVisible
);
725 nsIFrame
* cgFrame
= colFrame
->GetParent();
726 const nsStyleVisibility
* groupVis
= cgFrame
->StyleVisibility();
727 bool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
729 isCollapsed
= collapseCol
|| collapseGroup
;
731 space
+= aTableFrame
.GetColumnWidth(colX
);
733 if (!isCollapsed
&& aTableFrame
.ColumnHasCellSpacingBefore(colX
)) {
734 space
+= aTableFrame
.GetCellSpacingX(colX
- 1);
739 int32_t lastCol
= aColIndex
+ aColSpan
- 1;
740 for (colX
= aPrevColIndex
- 1; colX
> lastCol
; colX
--) {
741 bool isCollapsed
= false;
742 if (!aCheckVisibility
) {
743 space
+= aTableFrame
.GetColumnWidth(colX
);
746 nsTableColFrame
* colFrame
= aTableFrame
.GetColFrame(colX
);
747 const nsStyleVisibility
* colVis
= colFrame
->StyleVisibility();
748 bool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
== colVis
->mVisible
);
749 nsIFrame
* cgFrame
= colFrame
->GetParent();
750 const nsStyleVisibility
* groupVis
= cgFrame
->StyleVisibility();
751 bool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
753 isCollapsed
= collapseCol
|| collapseGroup
;
755 space
+= aTableFrame
.GetColumnWidth(colX
);
757 if (!isCollapsed
&& aTableFrame
.ColumnHasCellSpacingBefore(colX
)) {
758 space
+= aTableFrame
.GetCellSpacingX(colX
- 1);
765 // subtract the heights of aRow's prev in flows from the unpaginated height
767 nscoord
CalcHeightFromUnpaginatedHeight(nsPresContext
* aPresContext
,
768 nsTableRowFrame
& aRow
)
771 nsTableRowFrame
* firstInFlow
=
772 static_cast<nsTableRowFrame
*>(aRow
.FirstInFlow());
773 if (firstInFlow
->HasUnpaginatedHeight()) {
774 height
= firstInFlow
->GetUnpaginatedHeight(aPresContext
);
775 for (nsIFrame
* prevInFlow
= aRow
.GetPrevInFlow(); prevInFlow
;
776 prevInFlow
= prevInFlow
->GetPrevInFlow()) {
777 height
-= prevInFlow
->GetSize().height
;
780 return std::max(height
, 0);
784 nsTableRowFrame::ReflowChildren(nsPresContext
* aPresContext
,
785 nsHTMLReflowMetrics
& aDesiredSize
,
786 const nsHTMLReflowState
& aReflowState
,
787 nsTableFrame
& aTableFrame
,
788 nsReflowStatus
& aStatus
)
790 aStatus
= NS_FRAME_COMPLETE
;
792 // XXXldb Should we be checking constrained height instead?
793 const bool isPaginated
= aPresContext
->IsPaginated();
794 const bool borderCollapse
= aTableFrame
.IsBorderCollapse();
796 int32_t cellColSpan
= 1; // must be defined here so it's set properly for non-cell kids
798 nsTableIterator
iter(*this);
799 // remember the col index of the previous cell to handle rowspans into this row
800 int32_t firstPrevColIndex
= (iter
.IsLeftToRight()) ? -1 : aTableFrame
.GetColCount();
801 int32_t prevColIndex
= firstPrevColIndex
;
802 nscoord x
= 0; // running total of children x offset
804 // This computes the max of all cell heights
805 nscoord cellMaxHeight
= 0;
807 // Reflow each of our existing cell frames
808 for (nsIFrame
* kidFrame
= iter
.First(); kidFrame
; kidFrame
= iter
.Next()) {
809 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
811 // XXXldb nsCSSFrameConstructor needs to enforce this!
812 NS_NOTREACHED("yikes, a non-row child");
814 // it's an unknown frame type, give it a generic reflow and ignore the results
815 nsTableCellReflowState
816 kidReflowState(aPresContext
, aReflowState
, kidFrame
,
817 LogicalSize(kidFrame
->GetWritingMode(), 0, 0),
818 nsHTMLReflowState::CALLER_WILL_INIT
);
819 InitChildReflowState(*aPresContext
, nsSize(0,0), false, kidReflowState
);
820 nsHTMLReflowMetrics
desiredSize(aReflowState
);
821 nsReflowStatus status
;
822 ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
, 0, 0, 0, status
);
823 kidFrame
->DidReflow(aPresContext
, nullptr, nsDidReflowStatus::FINISHED
);
828 // See if we should only reflow the dirty child frames
829 bool doReflowChild
= true;
830 if (!aReflowState
.ShouldReflowAllKids() &&
831 !aTableFrame
.IsGeometryDirty() &&
832 !NS_SUBTREE_DIRTY(kidFrame
)) {
833 if (!aReflowState
.mFlags
.mSpecialHeightReflow
)
834 doReflowChild
= false;
836 else if ((NS_UNCONSTRAINEDSIZE
!= aReflowState
.AvailableHeight())) {
837 // We don't reflow a rowspan >1 cell here with a constrained height.
838 // That happens in nsTableRowGroupFrame::SplitSpanningCells.
839 if (aTableFrame
.GetEffectiveRowSpan(*cellFrame
) > 1) {
840 doReflowChild
= false;
843 if (aReflowState
.mFlags
.mSpecialHeightReflow
) {
844 if (!isPaginated
&& !(cellFrame
->GetStateBits() &
845 NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)) {
850 int32_t cellColIndex
;
851 cellFrame
->GetColIndex(cellColIndex
);
852 cellColSpan
= aTableFrame
.GetEffectiveColSpan(*cellFrame
);
854 // If the adjacent cell is in a prior row (because of a rowspan) add in the space
855 if ((iter
.IsLeftToRight() && (prevColIndex
!= (cellColIndex
- 1))) ||
856 (!iter
.IsLeftToRight() && (prevColIndex
!= cellColIndex
+ cellColSpan
))) {
857 x
+= GetSpaceBetween(prevColIndex
, cellColIndex
, cellColSpan
, aTableFrame
,
858 iter
.IsLeftToRight(), false);
861 // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into
862 prevColIndex
= (iter
.IsLeftToRight()) ? cellColIndex
+ (cellColSpan
- 1) : cellColIndex
;
864 // Reflow the child frame
865 nsRect kidRect
= kidFrame
->GetRect();
866 nsRect kidVisualOverflow
= kidFrame
->GetVisualOverflowRect();
868 (kidFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) != 0;
871 // Calculate the available width for the table cell using the known column widths
872 nscoord availCellWidth
=
873 CalcAvailWidth(aTableFrame
, *cellFrame
);
875 nsHTMLReflowMetrics
desiredSize(aReflowState
);
877 // If the avail width is not the same as last time we reflowed the cell or
878 // the cell wants to be bigger than what was available last time or
879 // it is a style change reflow or we are printing, then we must reflow the
880 // cell. Otherwise we can skip the reflow.
881 // XXXldb Why is this condition distinct from doReflowChild above?
882 WritingMode rowWM
= aReflowState
.GetWritingMode();
883 WritingMode cellWM
= cellFrame
->GetWritingMode();
884 LogicalSize cellDesiredSize
= cellFrame
->GetDesiredSize();
885 if ((availCellWidth
!= cellFrame
->GetPriorAvailWidth()) ||
886 (cellDesiredSize
.ISize(cellWM
) > cellFrame
->GetPriorAvailWidth()) ||
887 (GetStateBits() & NS_FRAME_IS_DIRTY
) ||
889 NS_SUBTREE_DIRTY(cellFrame
) ||
890 // See if it needs a special reflow, or if it had one that we need to undo.
891 (cellFrame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
) ||
893 // Reflow the cell to fit the available width, height
894 // XXX The old IR_ChildIsDirty code used availCellWidth here.
895 nsSize
kidAvailSize(availCellWidth
, aReflowState
.AvailableHeight());
898 nsTableCellReflowState
899 kidReflowState(aPresContext
, aReflowState
, kidFrame
,
900 LogicalSize(kidFrame
->GetWritingMode(),
902 nsHTMLReflowState::CALLER_WILL_INIT
);
903 InitChildReflowState(*aPresContext
, kidAvailSize
, borderCollapse
,
906 nsReflowStatus status
;
907 ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
,
910 // allow the table to determine if/how the table needs to be rebalanced
911 // If any of the cells are not complete, then we're not complete
912 if (NS_FRAME_IS_NOT_COMPLETE(status
)) {
913 aStatus
= NS_FRAME_NOT_COMPLETE
;
917 if (x
!= kidRect
.x
) {
918 kidFrame
->InvalidateFrameSubtree();
921 desiredSize
.SetSize(cellWM
, cellDesiredSize
);
922 desiredSize
.mOverflowAreas
= cellFrame
->GetOverflowAreas();
924 // if we are in a floated table, our position is not yet established, so we cannot reposition our views
925 // the containing block will do this for us after positioning the table
926 if (!aTableFrame
.IsFloating()) {
927 // Because we may have moved the frame we need to make sure any views are
928 // positioned properly. We have to do this, because any one of our parent
929 // frames could have moved and we have no way of knowing...
930 nsTableFrame::RePositionViews(kidFrame
);
934 if (NS_UNCONSTRAINEDSIZE
== aReflowState
.AvailableHeight()) {
935 if (!GetPrevInFlow()) {
936 // Calculate the cell's actual height given its pass2 height. This
937 // function takes into account the specified height (in the style)
938 CalculateCellActualHeight(cellFrame
, desiredSize
.Height());
940 // height may have changed, adjust descent to absorb any excess difference
942 if (!kidFrame
->GetFirstPrincipalChild()->GetFirstPrincipalChild()) {
943 ascent
= desiredSize
.BSize(rowWM
);
945 ascent
= ((nsTableCellFrame
*)kidFrame
)->GetCellBaseline();
947 nscoord descent
= desiredSize
.BSize(rowWM
) - ascent
;
948 UpdateHeight(desiredSize
.BSize(rowWM
), ascent
, descent
, &aTableFrame
, cellFrame
);
951 cellMaxHeight
= std::max(cellMaxHeight
, desiredSize
.Height());
952 int32_t rowSpan
= aTableFrame
.GetEffectiveRowSpan((nsTableCellFrame
&)*kidFrame
);
954 SetContentHeight(cellMaxHeight
);
959 desiredSize
.ISize(rowWM
) = availCellWidth
;
961 FinishReflowChild(kidFrame
, aPresContext
, desiredSize
, nullptr, x
, 0, 0);
963 nsTableFrame::InvalidateTableFrame(kidFrame
, kidRect
, kidVisualOverflow
,
966 x
+= desiredSize
.Width();
969 if (kidRect
.x
!= x
) {
970 // Invalidate the old position
971 kidFrame
->InvalidateFrameSubtree();
972 // move to the new position
973 kidFrame
->SetPosition(nsPoint(x
, kidRect
.y
));
974 nsTableFrame::RePositionViews(kidFrame
);
975 // invalidate the new position
976 kidFrame
->InvalidateFrameSubtree();
978 // we need to account for the cell's width even if it isn't reflowed
981 if (kidFrame
->GetNextInFlow()) {
982 aStatus
= NS_FRAME_NOT_COMPLETE
;
985 ConsiderChildOverflow(aDesiredSize
.mOverflowAreas
, kidFrame
);
986 x
+= aTableFrame
.GetCellSpacingX(cellColIndex
);
989 // just set our width to what was available. The table will calculate the width and not use our value.
990 aDesiredSize
.Width() = aReflowState
.AvailableWidth();
992 if (aReflowState
.mFlags
.mSpecialHeightReflow
) {
993 aDesiredSize
.Height() = mRect
.height
;
995 else if (NS_UNCONSTRAINEDSIZE
== aReflowState
.AvailableHeight()) {
996 aDesiredSize
.Height() = CalcHeight(aReflowState
);
997 if (GetPrevInFlow()) {
998 nscoord height
= CalcHeightFromUnpaginatedHeight(aPresContext
, *this);
999 aDesiredSize
.Height() = std::max(aDesiredSize
.Height(), height
);
1002 if (isPaginated
&& HasStyleHeight()) {
1003 // set the unpaginated height so next in flows can try to honor it
1004 SetHasUnpaginatedHeight(true);
1005 SetUnpaginatedHeight(aPresContext
, aDesiredSize
.Height());
1007 if (isPaginated
&& HasUnpaginatedHeight()) {
1008 aDesiredSize
.Height() = std::max(aDesiredSize
.Height(), GetUnpaginatedHeight(aPresContext
));
1012 else { // constrained height, paginated
1013 // Compute the height we should have from style (subtracting the
1014 // height from our prev-in-flows from the style height)
1015 nscoord styleHeight
= CalcHeightFromUnpaginatedHeight(aPresContext
, *this);
1016 if (styleHeight
> aReflowState
.AvailableHeight()) {
1017 styleHeight
= aReflowState
.AvailableHeight();
1018 NS_FRAME_SET_INCOMPLETE(aStatus
);
1020 aDesiredSize
.Height() = std::max(cellMaxHeight
, styleHeight
);
1022 aDesiredSize
.UnionOverflowAreasWithDesiredBounds();
1023 FinishAndStoreOverflow(&aDesiredSize
);
1026 /** Layout the entire row.
1027 * This method stacks cells horizontally according to HTML 4.0 rules.
1030 nsTableRowFrame::Reflow(nsPresContext
* aPresContext
,
1031 nsHTMLReflowMetrics
& aDesiredSize
,
1032 const nsHTMLReflowState
& aReflowState
,
1033 nsReflowStatus
& aStatus
)
1035 DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame");
1036 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
1038 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1039 const nsStyleVisibility
* rowVis
= StyleVisibility();
1040 bool collapseRow
= (NS_STYLE_VISIBILITY_COLLAPSE
== rowVis
->mVisible
);
1042 tableFrame
->SetNeedToCollapse(true);
1045 // see if a special height reflow needs to occur due to having a pct height
1046 nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState
);
1048 // See if we have a cell with specified/pct height
1049 InitHasCellWithStyleHeight(tableFrame
);
1051 ReflowChildren(aPresContext
, aDesiredSize
, aReflowState
, *tableFrame
, aStatus
);
1053 if (aPresContext
->IsPaginated() && !NS_FRAME_IS_FULLY_COMPLETE(aStatus
) &&
1054 ShouldAvoidBreakInside(aReflowState
)) {
1055 aStatus
= NS_INLINE_LINE_BREAK_BEFORE();
1058 // just set our width to what was available. The table will calculate the width and not use our value.
1059 aDesiredSize
.Width() = aReflowState
.AvailableWidth();
1061 // If our parent is in initial reflow, it'll handle invalidating our
1062 // entire overflow rect.
1063 if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW
) &&
1064 nsSize(aDesiredSize
.Width(), aDesiredSize
.Height()) != mRect
.Size()) {
1068 // Any absolutely-positioned children will get reflowed in
1069 // nsFrame::FixupPositionedTableParts in another pass, so propagate our
1070 // dirtiness to them before our parent clears our dirty bits.
1071 PushDirtyBitToAbsoluteFrames();
1073 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
1077 * This function is called by the row group frame's SplitRowGroup() code when
1078 * pushing a row frame that has cell frames that span into it. The cell frame
1079 * should be reflowed with the specified height
1082 nsTableRowFrame::ReflowCellFrame(nsPresContext
* aPresContext
,
1083 const nsHTMLReflowState
& aReflowState
,
1085 nsTableCellFrame
* aCellFrame
,
1086 nscoord aAvailableHeight
,
1087 nsReflowStatus
& aStatus
)
1089 // Reflow the cell frame with the specified height. Use the existing width
1090 nsRect cellRect
= aCellFrame
->GetRect();
1091 nsRect cellVisualOverflow
= aCellFrame
->GetVisualOverflowRect();
1093 nsSize
availSize(cellRect
.width
, aAvailableHeight
);
1094 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1095 bool borderCollapse
= tableFrame
->IsBorderCollapse();
1096 nsTableCellReflowState
1097 cellReflowState(aPresContext
, aReflowState
, aCellFrame
,
1098 LogicalSize(aCellFrame
->GetWritingMode(),
1100 nsHTMLReflowState::CALLER_WILL_INIT
);
1101 InitChildReflowState(*aPresContext
, availSize
, borderCollapse
, cellReflowState
);
1102 cellReflowState
.mFlags
.mIsTopOfPage
= aIsTopOfPage
;
1104 nsHTMLReflowMetrics
desiredSize(aReflowState
);
1106 ReflowChild(aCellFrame
, aPresContext
, desiredSize
, cellReflowState
,
1107 0, 0, NS_FRAME_NO_MOVE_FRAME
, aStatus
);
1108 bool fullyComplete
= NS_FRAME_IS_COMPLETE(aStatus
) && !NS_FRAME_IS_TRUNCATED(aStatus
);
1109 if (fullyComplete
) {
1110 desiredSize
.Height() = aAvailableHeight
;
1112 aCellFrame
->SetSize(nsSize(cellRect
.width
, desiredSize
.Height()));
1114 // Note: VerticallyAlignChild can affect the overflow rect.
1115 // XXX What happens if this cell has 'vertical-align: baseline' ?
1116 // XXX Why is it assumed that the cell's ascent hasn't changed ?
1117 if (fullyComplete
) {
1118 aCellFrame
->VerticallyAlignChild(mMaxCellAscent
);
1121 nsTableFrame::InvalidateTableFrame(aCellFrame
, cellRect
,
1123 (aCellFrame
->GetStateBits() &
1124 NS_FRAME_FIRST_REFLOW
) != 0);
1126 aCellFrame
->DidReflow(aPresContext
, nullptr, nsDidReflowStatus::FINISHED
);
1128 return desiredSize
.Height();
1132 nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset
,
1134 bool aCollapseGroup
,
1137 const nsStyleVisibility
* rowVis
= StyleVisibility();
1138 bool collapseRow
= (NS_STYLE_VISIBILITY_COLLAPSE
== rowVis
->mVisible
);
1139 nsTableFrame
* tableFrame
= static_cast<nsTableFrame
*>(
1140 nsTableFrame::GetTableFrame(this)->FirstInFlow());
1142 tableFrame
->SetNeedToCollapse(true);
1145 if (aRowOffset
!= 0) {
1146 // We're moving, so invalidate our old position
1147 InvalidateFrameSubtree();
1150 nsRect rowRect
= GetRect();
1151 nsRect oldRect
= rowRect
;
1152 nsRect oldVisualOverflow
= GetVisualOverflowRect();
1154 rowRect
.y
-= aRowOffset
;
1155 rowRect
.width
= aWidth
;
1156 nsOverflowAreas overflow
;
1159 if (aCollapseGroup
|| collapseRow
) {
1160 aDidCollapse
= true;
1161 shift
= rowRect
.height
;
1162 nsTableCellFrame
* cellFrame
= GetFirstCell();
1165 cellFrame
->GetRowIndex(rowIndex
);
1166 shift
+= tableFrame
->GetCellSpacingY(rowIndex
);
1168 nsRect cRect
= cellFrame
->GetRect();
1169 // If aRowOffset != 0, there's no point in invalidating the cells, since
1170 // we've already invalidated our overflow area. Note that we _do_ still
1171 // need to invalidate if our row is not moving, because the cell might
1172 // span out of this row, so invalidating our row rect won't do enough.
1173 if (aRowOffset
== 0) {
1177 cellFrame
->SetRect(cRect
);
1178 cellFrame
= cellFrame
->GetNextCell();
1181 shift
+= tableFrame
->GetCellSpacingY(GetRowIndex());
1185 else { // row is not collapsed
1186 nsTableIterator
iter(*this);
1187 // remember the col index of the previous cell to handle rowspans into this
1189 int32_t firstPrevColIndex
= (iter
.IsLeftToRight()) ? -1 :
1190 tableFrame
->GetColCount();
1191 int32_t prevColIndex
= firstPrevColIndex
;
1192 nscoord x
= 0; // running total of children x offset
1194 int32_t colIncrement
= iter
.IsLeftToRight() ? 1 : -1;
1196 nsIFrame
* kidFrame
= iter
.First();
1198 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
1200 int32_t cellColIndex
;
1201 cellFrame
->GetColIndex(cellColIndex
);
1202 int32_t cellColSpan
= tableFrame
->GetEffectiveColSpan(*cellFrame
);
1204 // If the adjacent cell is in a prior row (because of a rowspan) add in
1206 if ((iter
.IsLeftToRight() && (prevColIndex
!= (cellColIndex
- 1))) ||
1207 (!iter
.IsLeftToRight() &&
1208 (prevColIndex
!= cellColIndex
+ cellColSpan
))) {
1209 x
+= GetSpaceBetween(prevColIndex
, cellColIndex
, cellColSpan
,
1210 *tableFrame
, iter
.IsLeftToRight(),
1213 nsRect
cRect(x
, 0, 0, rowRect
.height
);
1215 // remember the rightmost (ltr) or leftmost (rtl) column this cell
1217 prevColIndex
= (iter
.IsLeftToRight()) ?
1218 cellColIndex
+ (cellColSpan
- 1) : cellColIndex
;
1219 int32_t startIndex
= (iter
.IsLeftToRight()) ?
1220 cellColIndex
: cellColIndex
+ (cellColSpan
- 1);
1221 int32_t actualColSpan
= cellColSpan
;
1222 bool isVisible
= false;
1223 for (int32_t colX
= startIndex
; actualColSpan
> 0;
1224 colX
+= colIncrement
, actualColSpan
--) {
1226 nsTableColFrame
* colFrame
= tableFrame
->GetColFrame(colX
);
1227 const nsStyleVisibility
* colVis
= colFrame
->StyleVisibility();
1228 bool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1230 nsIFrame
* cgFrame
= colFrame
->GetParent();
1231 const nsStyleVisibility
* groupVis
= cgFrame
->StyleVisibility();
1232 bool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1233 groupVis
->mVisible
);
1234 bool isCollapsed
= collapseCol
|| collapseGroup
;
1236 cRect
.width
+= tableFrame
->GetColumnWidth(colX
);
1238 if ((actualColSpan
> 1)) {
1239 nsTableColFrame
* nextColFrame
=
1240 tableFrame
->GetColFrame(colX
+ colIncrement
);
1241 const nsStyleVisibility
* nextColVis
=
1242 nextColFrame
->StyleVisibility();
1243 if ( (NS_STYLE_VISIBILITY_COLLAPSE
!= nextColVis
->mVisible
) &&
1244 tableFrame
->ColumnHasCellSpacingBefore(colX
+ colIncrement
)) {
1245 cRect
.width
+= tableFrame
->GetCellSpacingX(cellColIndex
);
1252 x
+= tableFrame
->GetCellSpacingX(cellColIndex
);
1253 int32_t actualRowSpan
= tableFrame
->GetEffectiveRowSpan(*cellFrame
);
1254 nsTableRowFrame
* rowFrame
= GetNextRow();
1255 for (actualRowSpan
--; actualRowSpan
> 0 && rowFrame
; actualRowSpan
--) {
1256 const nsStyleVisibility
* nextRowVis
= rowFrame
->StyleVisibility();
1257 bool collapseNextRow
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1258 nextRowVis
->mVisible
);
1259 if (!collapseNextRow
) {
1260 nsRect nextRect
= rowFrame
->GetRect();
1261 cRect
.height
+= nextRect
.height
+
1262 tableFrame
->GetCellSpacingY(rowFrame
->GetRowIndex());
1264 rowFrame
= rowFrame
->GetNextRow();
1267 nsRect oldCellRect
= cellFrame
->GetRect();
1268 nsRect oldCellVisualOverflow
= cellFrame
->GetVisualOverflowRect();
1270 if (aRowOffset
== 0 && cRect
.TopLeft() != oldCellRect
.TopLeft()) {
1271 // We're moving the cell. Invalidate the old overflow area
1272 cellFrame
->InvalidateFrameSubtree();
1275 cellFrame
->SetRect(cRect
);
1277 // XXXbz This looks completely bogus in the cases when we didn't
1278 // collapse the cell!
1279 nsRect
cellBounds(0, 0, cRect
.width
, cRect
.height
);
1280 nsOverflowAreas
cellOverflow(cellBounds
, cellBounds
);
1281 cellFrame
->FinishAndStoreOverflow(cellOverflow
, cRect
.Size());
1282 nsTableFrame::RePositionViews(cellFrame
);
1283 ConsiderChildOverflow(overflow
, cellFrame
);
1285 if (aRowOffset
== 0) {
1286 nsTableFrame::InvalidateTableFrame(cellFrame
, oldCellRect
,
1287 oldCellVisualOverflow
,
1291 kidFrame
= iter
.Next(); // Get the next child
1296 overflow
.UnionAllWith(nsRect(0, 0, rowRect
.width
, rowRect
.height
));
1297 FinishAndStoreOverflow(overflow
, rowRect
.Size());
1299 nsTableFrame::RePositionViews(this);
1300 nsTableFrame::InvalidateTableFrame(this, oldRect
, oldVisualOverflow
, false);
1305 * The following method is called by the row group frame's SplitRowGroup()
1306 * when it creates a continuing cell frame and wants to insert it into the
1310 nsTableRowFrame::InsertCellFrame(nsTableCellFrame
* aFrame
,
1313 // Find the cell frame where col index < aColIndex
1314 nsTableCellFrame
* priorCell
= nullptr;
1315 for (nsIFrame
* child
= mFrames
.FirstChild(); child
;
1316 child
= child
->GetNextSibling()) {
1317 nsTableCellFrame
*cellFrame
= do_QueryFrame(child
);
1320 cellFrame
->GetColIndex(colIndex
);
1321 if (colIndex
< aColIndex
) {
1322 priorCell
= cellFrame
;
1327 mFrames
.InsertFrame(this, priorCell
, aFrame
);
1331 nsTableRowFrame::GetType() const
1333 return nsGkAtoms::tableRowFrame
;
1337 nsTableRowFrame::GetNextRow() const
1339 nsIFrame
* childFrame
= GetNextSibling();
1340 while (childFrame
) {
1341 nsTableRowFrame
*rowFrame
= do_QueryFrame(childFrame
);
1343 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
== childFrame
->StyleDisplay()->mDisplay
, "wrong display type on rowframe");
1346 childFrame
= childFrame
->GetNextSibling();
1351 NS_DECLARE_FRAME_PROPERTY(RowUnpaginatedHeightProperty
, nullptr)
1354 nsTableRowFrame::SetUnpaginatedHeight(nsPresContext
* aPresContext
,
1357 NS_ASSERTION(!GetPrevInFlow(), "program error");
1359 aPresContext
->PropertyTable()->
1360 Set(this, RowUnpaginatedHeightProperty(), NS_INT32_TO_PTR(aValue
));
1364 nsTableRowFrame::GetUnpaginatedHeight(nsPresContext
* aPresContext
)
1366 FrameProperties props
= FirstInFlow()->Properties();
1367 return NS_PTR_TO_INT32(props
.Get(RowUnpaginatedHeightProperty()));
1370 void nsTableRowFrame::SetContinuousBCBorderWidth(uint8_t aForSide
,
1371 BCPixelSize aPixelValue
)
1375 mRightContBorderWidth
= aPixelValue
;
1378 mTopContBorderWidth
= aPixelValue
;
1381 mLeftContBorderWidth
= aPixelValue
;
1384 NS_ERROR("invalid NS_SIDE arg");
1387 #ifdef ACCESSIBILITY
1389 nsTableRowFrame::AccessibleType()
1391 return a11y::eHTMLTableRowType
;
1395 * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether
1396 * this row has any cells that have non-auto-height. (Row-spanning
1397 * cells are ignored.)
1399 void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame
* aTableFrame
)
1401 nsTableIterator
iter(*this);
1403 for (nsIFrame
* kidFrame
= iter
.First(); kidFrame
; kidFrame
= iter
.Next()) {
1404 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
1406 NS_NOTREACHED("Table row has a non-cell child.");
1409 // Ignore row-spanning cells
1410 const nsStyleCoord
&cellHeight
= cellFrame
->StylePosition()->mHeight
;
1411 if (aTableFrame
->GetEffectiveRowSpan(*cellFrame
) == 1 &&
1412 cellHeight
.GetUnit() != eStyleUnit_Auto
&&
1413 /* calc() with percentages treated like 'auto' */
1414 (!cellHeight
.IsCalcUnit() || !cellHeight
.HasPercent())) {
1415 AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT
);
1419 RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT
);
1423 nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey
)
1425 nsIFrame::InvalidateFrame(aDisplayItemKey
);
1426 GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey
);
1430 nsTableRowFrame::InvalidateFrameWithRect(const nsRect
& aRect
, uint32_t aDisplayItemKey
)
1432 nsIFrame::InvalidateFrameWithRect(aRect
, aDisplayItemKey
);
1433 // If we have filters applied that would affects our bounds, then
1434 // we get an inactive layer created and this is computed
1435 // within FrameLayerBuilder
1436 GetParent()->InvalidateFrameWithRect(aRect
+ GetPosition(), aDisplayItemKey
);
1439 /* ----- global methods ----- */
1442 NS_NewTableRowFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
1444 return new (aPresShell
) nsTableRowFrame(aContext
);
1447 NS_IMPL_FRAMEARENA_HELPERS(nsTableRowFrame
)
1449 #ifdef DEBUG_FRAME_DUMP
1451 nsTableRowFrame::GetFrameName(nsAString
& aResult
) const
1453 return MakeFrameName(NS_LITERAL_STRING("TableRow"), aResult
);