Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#ifndef nsTableFrame_h__
#define nsTableFrame_h__
#include "mozilla/Attributes.h"
#include "celldata.h"
#include "nscore.h"
#include "nsContainerFrame.h"
#include "nsStyleConsts.h"
#include "nsCellMap.h"
#include "nsGkAtoms.h"
#include "nsDisplayList.h"
#include "TableArea.h"
struct BCPaintBorderAction;
class nsTableCellFrame;
class nsTableCellMap;
class nsTableColFrame;
class nsTableRowGroupFrame;
class nsTableRowFrame;
class nsTableColGroupFrame;
class nsITableLayoutStrategy;
namespace mozilla {
class LogicalMargin;
class PresShell;
class WritingMode;
struct TableBCData;
struct TableReflowInput;
namespace layers {
class StackingContextHelper;
// An input to nsTableFrame::ReflowTable() and TableReflowInput.
enum class TableReflowMode : uint8_t {
// A reflow to measure the block-size of the table. We use this value to
// request an unconstrained available block in the first reflow if a second
// special block-size reflow is needed later.
// A final reflow with the available block-size in the table frame's
// ReflowInput.
class nsDisplayTableItem : public nsPaintedDisplayItem {
nsDisplayTableItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsPaintedDisplayItem(aBuilder, aFrame) {}
// With collapsed borders, parts of the collapsed border can extend outside
// the table part frames, so allow this display element to blow out to our
// overflow rect. This is also useful for row frames that have spanning
// cells extending outside them.
nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
class nsDisplayTableBackgroundSet {
nsDisplayList* ColGroupBackgrounds() { return &mColGroupBackgrounds; }
nsDisplayList* ColBackgrounds() { return &mColBackgrounds; }
nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable);
~nsDisplayTableBackgroundSet() {
mozilla::DebugOnly<nsDisplayTableBackgroundSet*> result =
MOZ_ASSERT(result == this);
* Move all display items in our lists to top of the corresponding lists in
* the destination.
void MoveTo(const nsDisplayListSet& aDestination) {
void AddColumn(nsTableColFrame* aFrame) { mColumns.AppendElement(aFrame); }
nsTableColFrame* GetColForIndex(int32_t aIndex) { return mColumns[aIndex]; }
const nsPoint& TableToReferenceFrame() { return mToReferenceFrame; }
const nsRect& GetDirtyRect() { return mDirtyRect; }
const DisplayItemClipChain* GetTableClipChain() {
return mCombinedTableClipChain;
const ActiveScrolledRoot* GetTableASR() { return mTableASR; }
layers::ScrollableLayerGuid::ViewID GetScrollParentId() {
return mCurrentScrollParentId;
// This class is only used on stack, so we don't have to worry about leaking
// it. Don't let us be heap-allocated!
void* operator new(size_t sz) noexcept(true);
nsDisplayListBuilder* mBuilder;
nsDisplayTableBackgroundSet* mPrevTableBackgroundSet;
nsDisplayList mColGroupBackgrounds;
nsDisplayList mColBackgrounds;
nsTArray<nsTableColFrame*> mColumns;
nsPoint mToReferenceFrame;
nsRect mDirtyRect;
layers::ScrollableLayerGuid::ViewID mCurrentScrollParentId;
const DisplayItemClipChain* mCombinedTableClipChain;
const ActiveScrolledRoot* mTableASR;
} // namespace mozilla
/* ========================================================================== */
enum nsTableColType {
eColContent = 0, // there is real col content associated
eColAnonymousCol = 1, // the result of a span on a col
eColAnonymousColGroup = 2, // the result of a span on a col group
eColAnonymousCell = 3 // the result of a cell alone
* nsTableFrame maps the inner portion of a table (everything except captions.)
* Used as a pseudo-frame within nsTableWrapperFrame, it may also be used
* stand-alone as the top-level frame.
* The principal child list contains row group frames. There is also an
* additional child list, FrameChildListID::ColGroup, which contains the col
* group frames.
class nsTableFrame : public nsContainerFrame {
typedef mozilla::image::ImgDrawResult ImgDrawResult;
typedef mozilla::WritingMode WritingMode;
typedef mozilla::LogicalMargin LogicalMargin;
typedef nsTArray<nsIFrame*> FrameTArray;
/** nsTableWrapperFrame has intimate knowledge of the inner table frame */
friend class nsTableWrapperFrame;
* instantiate a new instance of nsTableRowFrame.
* @param aPresShell the pres shell for this frame
* @return the frame that was created
friend nsTableFrame* NS_NewTableFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);
/** sets defaults for table-specific style.
* @see nsIFrame::Init
void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
// Return true if aParentReflowInput.frame or any of its ancestors within
// the containing table have non-auto bsize. (e.g. pct or fixed bsize)
static bool AncestorsHaveStyleBSize(const ReflowInput& aParentReflowInput);
// See if a special bsize reflow will occur due to having a pct bsize when
// the pct bsize basis may not yet be valid.
static void CheckRequestSpecialBSizeReflow(const ReflowInput& aReflowInput);
// Notify the frame and its ancestors (up to the containing table) that a
// special height reflow will occur.
static void RequestSpecialBSizeReflow(const ReflowInput& aReflowInput);
static void RePositionViews(nsIFrame* aFrame);
static bool PageBreakAfter(nsIFrame* aSourceFrame, nsIFrame* aNextFrame);
// Register or deregister a positioned table part with its nsTableFrame.
// These objects will be visited by FixupPositionedTableParts after reflow is
// complete. (See that function for more explanation.) Should be called
// during frame construction or style recalculation.
// @return true if the frame is a registered positioned table part.
static void PositionedTablePartMaybeChanged(
nsIFrame*, mozilla::ComputedStyle* aOldStyle);
// Unregister a positioned table part with its nsTableFrame, if needed.
static void MaybeUnregisterPositionedTablePart(nsIFrame* aFrame);
* Notification that rowspan or colspan has changed for content inside a
* table cell
void RowOrColSpanChanged(nsTableCellFrame* aCellFrame);
/** @see nsIFrame::DestroyFrom */
void Destroy(DestroyContext&) override;
/** @see nsIFrame::DidSetComputedStyle */
void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
void SetInitialChildList(ChildListID aListID,
nsFrameList&& aChildList) override;
void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override;
void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
const nsLineList::iterator* aPrevFrameLine,
nsFrameList&& aFrameList) override;
void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override;
nsMargin GetUsedBorder() const override;
nsMargin GetUsedPadding() const override;
nsMargin GetUsedMargin() const override;
/** helper method to find the table parent of any table frame object */
static nsTableFrame* GetTableFrame(nsIFrame* aSourceFrame);
// 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);
/** @return true if aDisplayType represents a rowgroup of any sort
* (header, footer, or body)
bool IsRowGroup(mozilla::StyleDisplay aDisplayType) const;
const nsFrameList& GetChildList(ChildListID aListID) const override;
void GetChildLists(nsTArray<ChildList>* aLists) const override;
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
/** Get the outer half (i.e., the part outside the height and width of
* the table) of the largest segment (?) of border-collapsed border on
* the table on each side, or 0 for non border-collapsed tables.
LogicalMargin GetOuterBCBorder(const WritingMode aWM) const;
* Emplace our border and padding in aBorder and aPadding if we are
* border-collapsed. Otherwise, do nothing.
void GetCollapsedBorderPadding(
mozilla::Maybe<mozilla::LogicalMargin>& aBorder,
mozilla::Maybe<mozilla::LogicalMargin>& aPadding) const;
friend class nsDelayedCalcBCBorders;
void AddBCDamageArea(const mozilla::TableArea& aValue);
bool BCRecalcNeeded(ComputedStyle* aOldComputedStyle,
ComputedStyle* aNewComputedStyle);
void PaintBCBorders(DrawTarget& aDrawTarget, const nsRect& aDirtyRect);
void CreateWebRenderCommandsForBCBorders(
mozilla::wr::DisplayListBuilder& aBuilder,
const mozilla::layers::StackingContextHelper& aSc,
const nsRect& aVisibleRect, const nsPoint& aOffsetToReferenceFrame);
void MarkIntrinsicISizesDirty() override;
// For border-collapse tables, the caller must not add padding and
// border to the results of these functions.
nscoord GetMinISize(gfxContext* aRenderingContext) override;
nscoord GetPrefISize(gfxContext* aRenderingContext) override;
IntrinsicSizeOffsetData IntrinsicISizeOffsets(
nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override;
SizeComputationResult ComputeSize(
gfxContext* aRenderingContext, mozilla::WritingMode aWM,
const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorderPadding,
const mozilla::StyleSizeOverrides& aSizeOverrides,
mozilla::ComputeSizeFlags aFlags) override;
mozilla::LogicalSize ComputeAutoSize(
gfxContext* aRenderingContext, mozilla::WritingMode aWM,
const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorderPadding,
const mozilla::StyleSizeOverrides& aSizeOverrides,
mozilla::ComputeSizeFlags aFlags) override;
* A copy of nsIFrame::ShrinkISizeToFit that calls a different
* GetPrefISize, since tables have two different ones.
nscoord TableShrinkISizeToFit(gfxContext* aRenderingContext,
nscoord aWidthInCB);
// clang-format off
* Inner tables are reflowed in two steps.
* <pre>
* if mFirstPassValid is false, this is our first time through since content was last changed
* set pass to 1
* do pass 1
* get min/max info for all cells in an infinite space
* do column balancing
* set mFirstPassValid to true
* do pass 2
* use column widths to Reflow cells
* </pre>
* @see nsIFrame::Reflow
// clang-format on
void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
void ReflowTable(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput,
const LogicalMargin& aBorderPadding,
mozilla::TableReflowMode aReflowMode,
nsIFrame*& aLastChildReflowed, nsReflowStatus& aStatus);
nsFrameList& GetColGroups();
ComputedStyle* GetParentComputedStyle(
nsIFrame** aProviderFrame) const override;
/** @see nsIFrame::GetFrameName */
nsresult GetFrameName(nsAString& aResult) const override;
/** Return the isize of the column at aColIndex.
* This may only be called on the table's first-in-flow.
nscoord GetColumnISizeFromFirstInFlow(int32_t aColIndex);
/** Helper to get the column spacing style value.
* The argument refers to the space between column aColIndex and column
* aColIndex + 1. An index of -1 indicates the padding between the table
* and the left border, an index equal to the number of columns indicates
* the padding between the table and the right border.
* Although in this class cell spacing does not depend on the index, it
* may be important for overriding classes.
virtual nscoord GetColSpacing(int32_t aColIndex);
/** Helper to find the sum of the cell spacing between arbitrary columns.
* The argument refers to the space between column aColIndex and column
* aColIndex + 1. An index of -1 indicates the padding between the table
* and the left border, an index equal to the number of columns indicates
* the padding between the table and the right border.
* This method is equivalent to
* nscoord result = 0;
* for (i = aStartColIndex; i < aEndColIndex; i++) {
* result += GetColSpacing(i);
* }
* return result;
virtual nscoord GetColSpacing(int32_t aStartColIndex, int32_t aEndColIndex);
/** Helper to get the row spacing style value.
* The argument refers to the space between row aRowIndex and row
* aRowIndex + 1. An index of -1 indicates the padding between the table
* and the top border, an index equal to the number of rows indicates
* the padding between the table and the bottom border.
* Although in this class cell spacing does not depend on the index, it
* may be important for overriding classes.
virtual nscoord GetRowSpacing(int32_t aRowIndex);
/** Helper to find the sum of the cell spacing between arbitrary rows.
* The argument refers to the space between row aRowIndex and row
* aRowIndex + 1. An index of -1 indicates the padding between the table
* and the top border, an index equal to the number of rows indicates
* the padding between the table and the bottom border.
* This method is equivalent to
* nscoord result = 0;
* for (i = aStartRowIndex; i < aEndRowIndex; i++) {
* result += GetRowSpacing(i);
* }
* return result;
virtual nscoord GetRowSpacing(int32_t aStartRowIndex, int32_t aEndRowIndex);
/* For the base implementation of nsTableFrame, cell spacing does not depend
* on row/column indexing.
nscoord GetColSpacing();
nscoord GetRowSpacing();
nscoord SynthesizeFallbackBaseline(
mozilla::WritingMode aWM,
BaselineSharingGroup aBaselineGroup) const override;
Maybe<nscoord> GetNaturalBaselineBOffset(
mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
BaselineExportContext) const override;
/** return the row span of a cell, taking into account row span magic at the
* bottom of a table. The row span equals the number of rows spanned by aCell
* starting at aStartRowIndex, and can be smaller if aStartRowIndex is greater
* than the row index in which aCell originates.
* @param aStartRowIndex the cell
* @param aCell the cell
* @return the row span, correcting for row spans that extend beyond the
* bottom of the table.
int32_t GetEffectiveRowSpan(int32_t aStartRowIndex,
const nsTableCellFrame& aCell) const;
int32_t GetEffectiveRowSpan(const nsTableCellFrame& aCell,
nsCellMap* aCellMap = nullptr);
/** return the col span of a cell, taking into account col span magic at the
* edge of a table.
* @param aCell the cell
* @return the col span, correcting for col spans that extend beyond the edge
* of the table.
int32_t GetEffectiveColSpan(const nsTableCellFrame& aCell,
nsCellMap* aCellMap = nullptr) const;
/** indicate whether the row has more than one cell that either originates
* or is spanned from the rows above
bool HasMoreThanOneCell(int32_t aRowIndex) const;
/** return the column frame associated with aColIndex
* returns nullptr if the col frame has not yet been allocated, or if
* aColIndex is out of range
nsTableColFrame* GetColFrame(int32_t aColIndex) const;
/** Insert a col frame reference into the colframe cache and adapt the cellmap
* @param aColFrame - the column frame
* @param aColIndex - index where the column should be inserted into the
* colframe cache
void InsertCol(nsTableColFrame& aColFrame, int32_t aColIndex);
nsTableColGroupFrame* CreateSyntheticColGroupFrame();
int32_t DestroyAnonymousColFrames(int32_t aNumFrames);
// Append aNumColsToAdd anonymous col frames of type eColAnonymousCell to our
// last synthetic colgroup. If we have no such colgroup, then create one.
void AppendAnonymousColFrames(int32_t aNumColsToAdd);
// Append aNumColsToAdd anonymous col frames of type aColType to
// aColGroupFrame. If aAddToTable is true, also call AddColsToTable on the
// new cols.
void AppendAnonymousColFrames(nsTableColGroupFrame* aColGroupFrame,
int32_t aNumColsToAdd, nsTableColType aColType,
bool aAddToTable);
void MatchCellMapToColCache(nsTableCellMap* aCellMap);
void DidResizeColumns();
void AppendCell(nsTableCellFrame& aCellFrame, int32_t aRowIndex);
void InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames, int32_t aRowIndex,
int32_t aColIndexBefore);
void RemoveCell(nsTableCellFrame* aCellFrame, int32_t aRowIndex);
void AppendRows(nsTableRowGroupFrame* aRowGroupFrame, int32_t aRowIndex,
nsTArray<nsTableRowFrame*>& aRowFrames);
int32_t InsertRows(nsTableRowGroupFrame* aRowGroupFrame,
nsTArray<nsTableRowFrame*>& aFrames, int32_t aRowIndex,
bool aConsiderSpans);
void RemoveRows(nsTableRowFrame& aFirstRowFrame, int32_t aNumRowsToRemove,
bool aConsiderSpans);
/** Insert multiple rowgroups into the table cellmap handling
* @param aRowGroups - iterator that iterates over the rowgroups to insert
void InsertRowGroups(const nsFrameList::Slice& aRowGroups);
void InsertColGroups(int32_t aStartColIndex,
const nsFrameList::Slice& aColgroups);
void RemoveCol(nsTableColGroupFrame* aColGroupFrame, int32_t aColIndex,
bool aRemoveFromCache, bool aRemoveFromCellMap);
bool ColumnHasCellSpacingBefore(int32_t aColIndex) const;
bool HasPctCol() const;
void SetHasPctCol(bool aValue);
bool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(bool aValue);
* To be called on a frame by its parent after setting its size/position and
* calling DidReflow (possibly via FinishReflowChild()). This can also be
* used for child frames which are not being reflowed but did have their size
* or position changed.
* @param aFrame The frame to invalidate
* @param aOrigRect The original rect of aFrame (before the change).
* @param aOrigInkOverflow The original overflow rect of aFrame.
* @param aIsFirstReflow True if the size/position change is due to the
* first reflow of aFrame.
static void InvalidateTableFrame(nsIFrame* aFrame, const nsRect& aOrigRect,
const nsRect& aOrigInkOverflow,
bool aIsFirstReflow);
bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) override;
// Return our wrapper frame.
void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
static void UpdateStyleOfOwnedAnonBoxesForTableWrapper(
nsIFrame* aOwningFrame, nsIFrame* aWrapperFrame,
mozilla::ServoRestyleState& aRestyleState);
/** protected constructor.
* @see NewFrame
explicit nsTableFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
ClassID aID = kClassID);
virtual ~nsTableFrame();
void InitChildReflowInput(ReflowInput& aReflowInput);
LogicalSides GetLogicalSkipSides() const override;
void IterateBCBorders(BCPaintBorderAction& aAction, const nsRect& aDirtyRect);
bool IsRowInserted() const;
void SetRowInserted(bool aValue);
// A helper function to reflow a header or footer with unconstrained
// block-size to see if it should be made repeatable.
// @return the desired block-size for a header or footer.
nscoord SetupHeaderFooterChild(const mozilla::TableReflowInput& aReflowInput,
nsTableRowGroupFrame* aFrame);
void ReflowChildren(mozilla::TableReflowInput& aReflowInput,
nsReflowStatus& aStatus, nsIFrame*& aLastChildReflowed,
mozilla::OverflowAreas& aOverflowAreas);
// This calls the col group and column reflow methods, which do two things:
// (1) set all the dimensions to 0
// (2) notify the table about colgroups or columns with hidden visibility
void ReflowColGroups(gfxContext* aRenderingContext);
/** return the isize of the table taking into account visibility collapse
* on columns and colgroups
* @param aBorderPadding the border and padding of the table
nscoord GetCollapsedISize(const WritingMode aWM,
const LogicalMargin& aBorderPadding);
/** Adjust the table for visibility.collapse set on rowgroups, rows,
* colgroups and cols
* @param aDesiredSize the metrics of the table
* @param aBorderPadding the border and padding of the table
void AdjustForCollapsingRowsCols(ReflowOutput& aDesiredSize,
const WritingMode aWM,
const LogicalMargin& aBorderPadding);
/** FixupPositionedTableParts is called at the end of table reflow to reflow
* the absolutely positioned descendants of positioned table parts. This is
* necessary because the dimensions of table parts may change after they've
* been reflowed (e.g. in AdjustForCollapsingRowsCols).
void FixupPositionedTableParts(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput);
// Clears the list of positioned table parts.
void ClearAllPositionedTableParts();
nsITableLayoutStrategy* LayoutStrategy() const {
return static_cast<nsTableFrame*>(FirstInFlow())
// Helper for InsertFrames.
void HomogenousInsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
nsFrameList& aFrameList);
/* Handle a row that got inserted during reflow. aNewHeight is the
new height of the table after reflow. */
void ProcessRowInserted(nscoord aNewHeight);
// Calculate the border-box block-size of this table, with the min-block-size,
// max-block-size, and intrinsic border-box block considered.
nscoord CalcBorderBoxBSize(const ReflowInput& aReflowInput,
const LogicalMargin& aBorderPadding,
nscoord aIntrinsicBorderBoxBSize);
// Calculate the desired block-size of this table.
// Note: this method is accurate after the children are reflowed. It might
// distribute extra block-size to table rows if the table has a specified
// block-size larger than the intrinsic block-size.
nscoord CalcDesiredBSize(const ReflowInput& aReflowInput,
const LogicalMargin& aBorderPadding,
const nsReflowStatus& aStatus);
// The following is a helper for CalcDesiredBSize
void DistributeBSizeToRows(const ReflowInput& aReflowInput, nscoord aAmount);
void PlaceChild(mozilla::TableReflowInput& aReflowInput, nsIFrame* aKidFrame,
const ReflowInput& aKidReflowInput,
const mozilla::LogicalPoint& aKidPosition,
const nsSize& aContainerSize, ReflowOutput& aKidDesiredSize,
const nsRect& aOriginalKidRect,
const nsRect& aOriginalKidInkOverflow);
void PlaceRepeatedFooter(mozilla::TableReflowInput& aReflowInput,
nsTableRowGroupFrame* aTfoot, nscoord aFooterBSize);
using RowGroupArray = AutoTArray<nsTableRowGroupFrame*, 8>;
// Push all our non-repeatable child frames from the aRowGroups array, in
// order, starting from the frame at aPushFrom to the end of the array. The
// pushed frames are put on our overflow list. This is a table specific
// version that takes into account repeated header and footer frames when
// continuing table frames.
void PushChildrenToOverflow(const RowGroupArray& aRowGroups,
size_t aPushFrom);
// Return the children frames in the display order (e.g. thead before tbodies
// before tfoot). If there are multiple theads or tfoots, all but the first
// one are treated as tbodies instead.
// @param aHead Outparam for the first thead if there is any.
// @param aFoot Outparam for the first tfoot if there is any.
RowGroupArray OrderedRowGroups(nsTableRowGroupFrame** aHead = nullptr,
nsTableRowGroupFrame** aFoot = nullptr) const;
// Returns true if there are any cells above the row at
// aRowIndex and spanning into the row at aRowIndex, the number of
// effective columns limits the search up to that column
bool RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols);
// Returns true if there is a cell originating in aRowIndex
// which spans into the next row, the number of effective
// columns limits the search up to that column
bool RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols);
bool HaveReflowedColGroups() const;
void SetHaveReflowedColGroups(bool aValue);
bool IsBorderCollapse() const;
bool NeedToCalcBCBorders() const;
void SetNeedToCalcBCBorders(bool aValue);
bool NeedToCollapse() const;
void SetNeedToCollapse(bool aValue);
bool NeedToCalcHasBCBorders() const;
void SetNeedToCalcHasBCBorders(bool aValue);
void CalcHasBCBorders();
bool HasBCBorders();
void SetHasBCBorders(bool aValue);
/** The GeometryDirty bit is similar to the NS_FRAME_IS_DIRTY frame
* state bit, which implies that all descendants are dirty. The
* GeometryDirty still implies that all the parts of the table are
* dirty, but resizing optimizations should still apply to the
* contents of the individual cells.
void SetGeometryDirty() { mBits.mGeometryDirty = true; }
void ClearGeometryDirty() { mBits.mGeometryDirty = false; }
bool IsGeometryDirty() const { return mBits.mGeometryDirty; }
/** Get the cell map for this table frame. It is not always mCellMap.
* Only the firstInFlow has a legit cell map
nsTableCellMap* GetCellMap() const;
/** Iterate over the row groups and adjust the row indices of all rows
* whose index is >= aRowIndex.
* @param aRowIndex - start adjusting with this index
* @param aAdjustment - shift the row index by this amount
void AdjustRowIndices(int32_t aRowIndex, int32_t aAdjustment);
/** Reset the rowindices of all rows as they might have changed due to
* rowgroup reordering, exclude new row group frames that show in the
* reordering but are not yet inserted into the cellmap
* @param aRowGroupsToExclude - an iterator that will produce the row groups
* to exclude.
void ResetRowIndices(const nsFrameList::Slice& aRowGroupsToExclude);
nsTArray<nsTableColFrame*>& GetColCache();
mozilla::TableBCData* GetTableBCData() const;
void SetBorderCollapse(bool aValue);
mozilla::TableBCData* GetOrCreateTableBCData();
void SetFullBCDamageArea();
void CalcBCBorders();
void ExpandBCDamageArea(mozilla::TableArea& aRect) const;
void SetColumnDimensions(nscoord aHeight, WritingMode aWM,
const LogicalMargin& aBorderPadding,
const nsSize& aContainerSize);
int32_t CollectRows(nsIFrame* aFrame,
nsTArray<nsTableRowFrame*>& aCollection);
public: /* ----- Cell Map public methods ----- */
int32_t GetStartRowIndex(const nsTableRowGroupFrame* aRowGroupFrame) const;
/** returns the number of rows in this table.
int32_t GetRowCount() const { return GetCellMap()->GetRowCount(); }
/** returns the number of columns in this table after redundant columns have
* been removed
int32_t GetEffectiveColCount() const;
/* return the col count including dead cols */
int32_t GetColCount() const { return GetCellMap()->GetColCount(); }
// return the last col index which isn't of type eColAnonymousCell
int32_t GetIndexOfLastRealCol();
/** returns true if table-layout:auto */
bool IsAutoLayout();
/* ---------- Row index management methods ------------ */
/** Add the given index to the existing ranges of
* deleted row indices and merge ranges if, with the addition of the new
* index, they become consecutive.
* @param aDeletedRowStoredIndex - index of the row that was deleted
* Note - 'stored' index here refers to the index that was assigned to
* the row before any remove row operations were performed i.e. the
* value of mRowIndex and not the value returned by GetRowIndex()
void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex);
/** Calculate the change that aStoredIndex must be increased/decreased by
* to get new index.
* Note that aStoredIndex is always the index of an undeleted row (since
* rows that have already been deleted can never call this method).
* @param aStoredIndex - The stored index value that must be adjusted
* Note - 'stored' index here refers to the index that was assigned to
* the row before any remove row operations were performed i.e. the
* value of mRowIndex and not the value returned by GetRowIndex()
int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex);
/** Returns whether mDeletedRowIndexRanges is empty
bool IsDeletedRowIndexRangesEmpty() const {
return mDeletedRowIndexRanges.empty();
bool IsDestroying() const { return mBits.mIsDestroying; }
#ifdef DEBUG
void Dump(bool aDumpRows, bool aDumpCols, bool aDumpCellMap);
* Helper method for RemoveFrame.
void DoRemoveFrame(DestroyContext&, ChildListID, nsIFrame*);
#ifdef DEBUG
void DumpRowGroup(nsIFrame* aChildFrame);
AutoTArray<nsTableColFrame*, 8> mColFrames;
struct TableBits {
uint32_t mHaveReflowedColGroups : 1; // have the col groups gotten their
// initial reflow
uint32_t mHasPctCol : 1; // does any cell or col have a pct width
uint32_t mCellSpansPctCol : 1; // does any cell span a col with a pct width
// (or containing a cell with a pct width)
uint32_t mIsBorderCollapse : 1; // border collapsing model vs. separate
// model
uint32_t mRowInserted : 1;
uint32_t mNeedToCalcBCBorders : 1;
uint32_t mGeometryDirty : 1;
uint32_t mNeedToCollapse : 1; // rows, cols that have visibility:collapse
// need to be collapsed
uint32_t mResizedColumns : 1; // have we resized columns since last reflow?
uint32_t mNeedToCalcHasBCBorders : 1;
uint32_t mHasBCBorders : 1;
uint32_t mIsDestroying : 1; // Whether we're in the process of destroying
// this table frame.
} mBits;
std::map<int32_t, int32_t> mDeletedRowIndexRanges; // maintains ranges of row
// indices of deleted rows
mozilla::UniquePtr<nsTableCellMap> mCellMap; // maintains the relationships
// between rows, cols, and cells
// the layout strategy for this frame
mozilla::UniquePtr<nsITableLayoutStrategy> mTableLayoutStrategy;
nsFrameList mColGroups; // the list of colgroup frames
inline bool nsTableFrame::IsRowGroup(mozilla::StyleDisplay aDisplayType) const {
return mozilla::StyleDisplay::TableHeaderGroup == aDisplayType ||
mozilla::StyleDisplay::TableFooterGroup == aDisplayType ||
mozilla::StyleDisplay::TableRowGroup == aDisplayType;
inline void nsTableFrame::SetHaveReflowedColGroups(bool aValue) {
mBits.mHaveReflowedColGroups = aValue;
inline bool nsTableFrame::HaveReflowedColGroups() const {
return (bool)mBits.mHaveReflowedColGroups;
inline bool nsTableFrame::HasPctCol() const { return (bool)mBits.mHasPctCol; }
inline void nsTableFrame::SetHasPctCol(bool aValue) {
mBits.mHasPctCol = (unsigned)aValue;
inline bool nsTableFrame::HasCellSpanningPctCol() const {
return (bool)mBits.mCellSpansPctCol;
inline void nsTableFrame::SetHasCellSpanningPctCol(bool aValue) {
mBits.mCellSpansPctCol = (unsigned)aValue;
inline bool nsTableFrame::IsRowInserted() const {
return (bool)mBits.mRowInserted;
inline void nsTableFrame::SetRowInserted(bool aValue) {
mBits.mRowInserted = (unsigned)aValue;
inline void nsTableFrame::SetNeedToCollapse(bool aValue) {
static_cast<nsTableFrame*>(FirstInFlow())->mBits.mNeedToCollapse =
inline bool nsTableFrame::NeedToCollapse() const {
return (bool)static_cast<nsTableFrame*>(FirstInFlow())->mBits.mNeedToCollapse;
inline nsFrameList& nsTableFrame::GetColGroups() {
return static_cast<nsTableFrame*>(FirstInFlow())->mColGroups;
inline nsTArray<nsTableColFrame*>& nsTableFrame::GetColCache() {
return mColFrames;
inline bool nsTableFrame::IsBorderCollapse() const {
return (bool)mBits.mIsBorderCollapse;
inline void nsTableFrame::SetBorderCollapse(bool aValue) {
mBits.mIsBorderCollapse = aValue;
inline bool nsTableFrame::NeedToCalcBCBorders() const {
return (bool)mBits.mNeedToCalcBCBorders;
inline void nsTableFrame::SetNeedToCalcBCBorders(bool aValue) {
mBits.mNeedToCalcBCBorders = (unsigned)aValue;
inline bool nsTableFrame::NeedToCalcHasBCBorders() const {
return (bool)mBits.mNeedToCalcHasBCBorders;
inline void nsTableFrame::SetNeedToCalcHasBCBorders(bool aValue) {
mBits.mNeedToCalcHasBCBorders = (unsigned)aValue;
inline bool nsTableFrame::HasBCBorders() {
if (NeedToCalcHasBCBorders()) {
return (bool)mBits.mHasBCBorders;
inline void nsTableFrame::SetHasBCBorders(bool aValue) {
mBits.mHasBCBorders = (unsigned)aValue;
#define ABORT0() \
{ \
NS_ASSERTION(false, "CellIterator program error"); \
return; \
#define ABORT1(aReturn) \
{ \
NS_ASSERTION(false, "CellIterator program error"); \
return aReturn; \