зеркало из https://github.com/mozilla/gecko-dev.git
953 строки
36 KiB
C++
953 строки
36 KiB
C++
/* -*- 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 http://mozilla.org/MPL/2.0/. */
|
|
#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.
|
|
Measuring,
|
|
|
|
// A final reflow with the available block-size in the table frame's
|
|
// ReflowInput.
|
|
Final,
|
|
};
|
|
|
|
class nsDisplayTableItem : public nsPaintedDisplayItem {
|
|
public:
|
|
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 {
|
|
public:
|
|
nsDisplayList* ColGroupBackgrounds() { return &mColGroupBackgrounds; }
|
|
|
|
nsDisplayList* ColBackgrounds() { return &mColBackgrounds; }
|
|
|
|
nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable);
|
|
|
|
~nsDisplayTableBackgroundSet() {
|
|
mozilla::DebugOnly<nsDisplayTableBackgroundSet*> result =
|
|
mBuilder->SetTableBackgroundSet(mPrevTableBackgroundSet);
|
|
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) {
|
|
aDestination.BorderBackground()->AppendToTop(ColGroupBackgrounds());
|
|
aDestination.BorderBackground()->AppendToTop(ColBackgrounds());
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
private:
|
|
// This class is only used on stack, so we don't have to worry about leaking
|
|
// it. Don't let us be heap-allocated!
|
|
void* operator new(size_t sz) noexcept(true);
|
|
|
|
protected:
|
|
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;
|
|
|
|
public:
|
|
NS_DECL_FRAMEARENA_HELPERS(nsTableFrame)
|
|
|
|
typedef nsTArray<nsIFrame*> FrameTArray;
|
|
NS_DECLARE_FRAME_PROPERTY_DELETABLE(PositionedTablePartArray, 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;
|
|
|
|
/** Same as above, but only if it's included from the border-box width
|
|
* of the table.
|
|
*/
|
|
LogicalMargin GetIncludedOuterBCBorder(const WritingMode aWM) const;
|
|
|
|
/** Same as above, but only if it's excluded from the border-box width
|
|
* of the table. This is the area that leaks out into the margin
|
|
* (or potentially past it, if there is no margin).
|
|
*/
|
|
LogicalMargin GetExcludedOuterBCBorder(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);
|
|
|
|
// XXXldb REWRITE THIS COMMENT!
|
|
// 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;
|
|
|
|
#ifdef DEBUG_FRAME_DUMP
|
|
/** @see nsIFrame::GetFrameName */
|
|
nsresult GetFrameName(nsAString& aResult) const override;
|
|
#endif
|
|
|
|
/** 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);
|
|
|
|
private:
|
|
/* For the base implementation of nsTableFrame, cell spacing does not depend
|
|
* on row/column indexing.
|
|
*/
|
|
nscoord GetColSpacing();
|
|
nscoord GetRowSpacing();
|
|
|
|
public:
|
|
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;
|
|
|
|
protected:
|
|
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);
|
|
|
|
public:
|
|
bool IsRowInserted() const;
|
|
void SetRowInserted(bool aValue);
|
|
|
|
protected:
|
|
// 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())
|
|
->mTableLayoutStrategy.get();
|
|
}
|
|
|
|
// Helper for InsertFrames.
|
|
void HomogenousInsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
|
|
nsFrameList& aFrameList);
|
|
|
|
private:
|
|
/* Handle a row that got inserted during reflow. aNewHeight is the
|
|
new height of the table after reflow. */
|
|
void ProcessRowInserted(nscoord aNewHeight);
|
|
|
|
protected:
|
|
// 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);
|
|
|
|
// 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);
|
|
|
|
public:
|
|
using RowGroupArray = AutoTArray<nsTableRowGroupFrame*, 8>;
|
|
|
|
protected:
|
|
// 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);
|
|
|
|
public:
|
|
// 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);
|
|
|
|
protected:
|
|
bool HaveReflowedColGroups() const;
|
|
void SetHaveReflowedColGroups(bool aValue);
|
|
|
|
public:
|
|
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;
|
|
|
|
protected:
|
|
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();
|
|
|
|
public:
|
|
/* ---------- 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; }
|
|
|
|
public:
|
|
#ifdef DEBUG
|
|
void Dump(bool aDumpRows, bool aDumpCols, bool aDumpCellMap);
|
|
#endif
|
|
|
|
protected:
|
|
/**
|
|
* Helper method for RemoveFrame.
|
|
*/
|
|
void DoRemoveFrame(DestroyContext&, ChildListID, nsIFrame*);
|
|
#ifdef DEBUG
|
|
void DumpRowGroup(nsIFrame* aChildFrame);
|
|
#endif
|
|
// DATA MEMBERS
|
|
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 =
|
|
(unsigned)aValue;
|
|
}
|
|
|
|
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()) {
|
|
CalcHasBCBorders();
|
|
SetNeedToCalcHasBCBorders(false);
|
|
}
|
|
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; \
|
|
}
|
|
|
|
#endif
|