diff options
Diffstat (limited to 'layout/tables/nsTableRowGroupFrame.h')
-rw-r--r-- | layout/tables/nsTableRowGroupFrame.h | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h new file mode 100644 index 0000000000..1ee23768b9 --- /dev/null +++ b/layout/tables/nsTableRowGroupFrame.h @@ -0,0 +1,411 @@ +/* -*- 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 nsTableRowGroupFrame_h__ +#define nsTableRowGroupFrame_h__ + +#include "mozilla/Attributes.h" +#include "nscore.h" +#include "nsContainerFrame.h" +#include "nsAtom.h" +#include "nsILineIterator.h" +#include "nsTArray.h" +#include "nsTableFrame.h" +#include "mozilla/WritingModes.h" + +class nsTableRowFrame; +namespace mozilla { +class PresShell; +struct TableRowGroupReflowInput; +} // namespace mozilla + +#define MIN_ROWS_NEEDING_CURSOR 20 + +/** + * nsTableRowGroupFrame is the frame that maps row groups + * (HTML tags THEAD, TFOOT, and TBODY). This class cannot be reused + * outside of an nsTableFrame. It assumes that its parent is an nsTableFrame, + * and its children are nsTableRowFrames. + * + * @see nsTableFrame + * @see nsTableRowFrame + */ +class nsTableRowGroupFrame final : public nsContainerFrame, + public nsILineIterator { + using TableRowGroupReflowInput = mozilla::TableRowGroupReflowInput; + + public: + NS_DECL_QUERYFRAME + NS_DECL_FRAMEARENA_HELPERS(nsTableRowGroupFrame) + + /** instantiate a new instance of nsTableRowFrame. + * @param aPresShell the pres shell for this frame + * + * @return the frame that was created + */ + friend nsTableRowGroupFrame* NS_NewTableRowGroupFrame( + mozilla::PresShell* aPresShell, ComputedStyle* aStyle); + virtual ~nsTableRowGroupFrame(); + + // nsIFrame overrides + void Init(nsIContent* aContent, nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) override { + nsContainerFrame::Init(aContent, aParent, aPrevInFlow); + if (!aPrevInFlow) { + mWritingMode = GetTableFrame()->GetWritingMode(); + } + } + + void Destroy(DestroyContext&) override; + + /** @see nsIFrame::DidSetComputedStyle */ + void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) 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 GetUsedMargin() const override; + nsMargin GetUsedBorder() const override; + nsMargin GetUsedPadding() const override; + + void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists) override; + + /** + * Calls Reflow for all of its child rows. + * + * Rows are all set to the same isize and stacked in the block direction. + * + * Rows are not split unless absolutely necessary. + * + * @param aDesiredSize isize set to isize of rows, bsize set to + * sum of bsize of rows that fit in AvailableBSize. + * + * @see nsIFrame::Reflow + */ + void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) override; + + bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) override; + +#ifdef DEBUG_FRAME_DUMP + nsresult GetFrameName(nsAString& aResult) const override; +#endif + + nsTableRowFrame* GetFirstRow(); + nsTableRowFrame* GetLastRow(); + + nsTableFrame* GetTableFrame() const { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->IsTableFrame()); + return static_cast<nsTableFrame*>(parent); + } + + /** return the number of child rows (not necessarily == number of child + * frames) */ + int32_t GetRowCount() const; + + /** return the table-relative row index of the first row in this rowgroup. + * if there are no rows, -1 is returned. + */ + int32_t GetStartRowIndex() const; + + /** 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 anAdjustment); + + // See nsTableFrame.h + int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex); + + /* mark rows starting from aStartRowFrame to the next 'aNumRowsToRemove-1' + * number of rows as deleted + */ + void MarkRowsAsDeleted(nsTableRowFrame& aStartRowFrame, + int32_t aNumRowsToDelete); + + // See nsTableFrame.h + void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex); + + /** + * Used for header and footer row group frames that are repeated when + * splitting a table frame. + * + * Performs any table specific initialization + * + * @param aHeaderFooterFrame the original header or footer row group frame + * that was repeated + */ + nsresult InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame); + + /** + * Get the total bsize of all the row rects + */ + nscoord GetBSizeBasis(const ReflowInput& aReflowInput); + + mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get bstart border from previous row group or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.BStart() + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(mozilla::WritingMode aWM, + mozilla::LogicalMargin& aBorder); + + /** + * Sets full border widths before collapsing with cell borders + * @param aForSide - side to set; only IEnd, IStart, BEnd are valid + */ + void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide, + BCPixelSize aPixelValue); + /** + * Adjust to the effect of visibility:collapse on the row group and + * its children + * @return additional shift bstart-wards that should be applied + * to subsequent rowgroups due to rows and this + * rowgroup being collapsed + * @param aBTotalOffset the total amount that the rowgroup is shifted + * @param aISize new isize of the rowgroup + * @param aWM the table's writing mode + */ + nscoord CollapseRowGroupIfNecessary(nscoord aBTotalOffset, nscoord aISize, + mozilla::WritingMode aWM); + + // nsILineIterator methods + public: + // The table row is the equivalent to a line in block layout. + // The nsILineIterator assumes that a line resides in a block, this role is + // fullfilled by the row group. Rows in table are counted relative to the + // table. The row index of row corresponds to the cellmap coordinates. The + // line index with respect to a row group can be computed by substracting the + // row index of the first row in the row group. + + /** Get the number of rows in a row group + * @return the number of lines in a row group + */ + int32_t GetNumLines() const final; + + /** @see nsILineIterator.h IsLineIteratorFlowRTL */ + bool IsLineIteratorFlowRTL() final; + + /** Return structural information about a line. */ + Result<LineInfo, nsresult> GetLine(int32_t aLineNumber) final; + + /** Given a frame that's a child of the rowgroup, find which line its on. + * @param aFrame - frame, should be a row + * @param aStartLine - minimal index to return + * @return row index relative to the row group if this a row + * frame and the index is at least aStartLine. + * -1 if the frame cannot be found. + */ + int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) final; + + /** Find the orginating cell frame on a row that is the nearest to the + * inline-dir coordinate of aPos. + * @param aLineNumber - the index of the row relative to the row group + * @param aPos - coordinate in twips relative to the + * origin of the row group + * @param aFrameFound - pointer to the cellframe + * @param aPosIsBeforeFirstFrame - the point is before the first originating + * cellframe + * @param aPosIsAfterLastFrame - the point is after the last originating + * cellframe + */ + NS_IMETHOD FindFrameAt(int32_t aLineNumber, nsPoint aPos, + nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame, + bool* aPosIsAfterLastFrame) final; + + /** Check whether visual and logical order of cell frames within a line are + * identical. As the layout will reorder them this is always the case + * @param aLine - the index of the row relative to the table + * @param aIsReordered - returns false + * @param aFirstVisual - if the table is rtl first originating cell frame + * @param aLastVisual - if the table is rtl last originating cell frame + */ + + NS_IMETHOD CheckLineOrder(int32_t aLine, bool* aIsReordered, + nsIFrame** aFirstVisual, + nsIFrame** aLastVisual) final; + + // row cursor methods to speed up searching for the row(s) + // containing a point. The basic idea is that we set the cursor + // property if the rows' y and yMosts are non-decreasing (considering only + // rows with nonempty overflowAreas --- empty overflowAreas never participate + // in event handling or painting), and the rowgroup has sufficient number of + // rows. The cursor property points to a "recently used" row. If we get a + // series of requests that work on rows "near" the cursor, then we can find + // those nearby rows quickly by starting our search at the cursor. + // This code is based on the line cursor code in nsBlockFrame. It's more + // general though, and could be extracted and used elsewhere. + struct FrameCursorData { + nsTArray<nsIFrame*> mFrames; + uint32_t mCursorIndex; + nscoord mOverflowAbove; + nscoord mOverflowBelow; + + FrameCursorData() + : mFrames(MIN_ROWS_NEEDING_CURSOR), + mCursorIndex(0), + mOverflowAbove(0), + mOverflowBelow(0) {} + + bool AppendFrame(nsIFrame* aFrame); + + void FinishBuildingCursor() { mFrames.Compact(); } + }; + + // Clear out row cursor because we're disturbing the rows (e.g., Reflow) + void ClearRowCursor(); + + /** + * Get the first row that might contain y-coord 'aY', or nullptr if you must + * search all rows. + * The actual row returned might not contain 'aY', but if not, it is + * guaranteed to be before any row which does contain 'aY'. + * aOverflowAbove is the maximum over all rows of -row.GetOverflowRect().y. + * To find all rows that intersect the vertical interval aY/aYMost, call + * GetFirstRowContaining(aY, &overflowAbove), and then iterate through all + * rows until reaching a row where row->GetRect().y - overflowAbove >= aYMost. + * That row and all subsequent rows cannot intersect the interval. + */ + nsIFrame* GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove); + + /** + * Set up the row cursor. After this, call AppendFrame for every + * child frame in sibling order. Ensure that the child frame y and YMost + * values form non-decreasing sequences (should always be true for table + * rows); if this is violated, call ClearRowCursor(). If we return nullptr, + * then we decided not to use a cursor or we already have one set up. + */ + FrameCursorData* SetupRowCursor(); + + bool CanProvideLineIterator() const final { return true; } + nsILineIterator* GetLineIterator() final { return this; } + + bool IsFrameOfType(uint32_t aFlags) const override { + if (aFlags & (eSupportsContainLayoutAndPaint | eSupportsAspectRatio)) { + return false; + } + + return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart)); + } + + void InvalidateFrame(uint32_t aDisplayItemKey = 0, + bool aRebuildDisplayItems = true) override; + void InvalidateFrameWithRect(const nsRect& aRect, + uint32_t aDisplayItemKey = 0, + bool aRebuildDisplayItems = true) override; + void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); } + + protected: + explicit nsTableRowGroupFrame(ComputedStyle* aStyle, + nsPresContext* aPresContext); + + void InitChildReflowInput(nsPresContext& aPresContext, bool aBorderCollapse, + ReflowInput& aReflowInput); + + LogicalSides GetLogicalSkipSides() const override; + + void PlaceChild(nsPresContext* aPresContext, + TableRowGroupReflowInput& aReflowInput, nsIFrame* aKidFrame, + const ReflowInput& aKidReflowInput, mozilla::WritingMode aWM, + const mozilla::LogicalPoint& aKidPosition, + const nsSize& aContainerSize, ReflowOutput& aDesiredSize, + const nsRect& aOriginalKidRect, + const nsRect& aOriginalKidInkOverflow); + + void CalculateRowBSizes(nsPresContext* aPresContext, + ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput); + + void DidResizeRows(ReflowOutput& aDesiredSize); + + /** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aReflowInput current inline state + */ + void ReflowChildren(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, + TableRowGroupReflowInput& aReflowInput, + nsReflowStatus& aStatus, + bool* aPageBreakBeforeEnd = nullptr); + + nsresult SplitRowGroup(nsPresContext* aPresContext, + ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsTableFrame* aTableFrame, nsReflowStatus& aStatus, + bool aRowForcedPageBreak); + + void SplitSpanningCells(nsPresContext& aPresContext, + const ReflowInput& aReflowInput, + nsTableFrame& aTableFrame, nsTableRowFrame& aFirstRow, + nsTableRowFrame& aLastRow, bool aFirstRowIsTopOfPage, + nscoord aSpanningRowBottom, + nsTableRowFrame*& aContRowFrame, + nsTableRowFrame*& aFirstTruncatedRow, + nscoord& aDesiredHeight); + + void CreateContinuingRowFrame(nsIFrame& aRowFrame, nsIFrame** aContRowFrame); + + bool IsSimpleRowFrame(nsTableFrame* aTableFrame, nsTableRowFrame* aRowFrame); + + void GetNextRowSibling(nsIFrame** aRowFrame); + + void UndoContinuedRow(nsPresContext* aPresContext, nsTableRowFrame* aRow); + + private: + // border widths in pixels in the collapsing border model + BCPixelSize mIEndContBorderWidth = 0; + BCPixelSize mBEndContBorderWidth = 0; + BCPixelSize mIStartContBorderWidth = 0; + + public: + bool IsRepeatable() const; + void SetRepeatable(bool aRepeatable); + bool HasStyleBSize() const; + void SetHasStyleBSize(bool aValue); + bool HasInternalBreakBefore() const; + bool HasInternalBreakAfter() const; +}; + +inline bool nsTableRowGroupFrame::IsRepeatable() const { + return HasAnyStateBits(NS_ROWGROUP_REPEATABLE); +} + +inline void nsTableRowGroupFrame::SetRepeatable(bool aRepeatable) { + if (aRepeatable) { + AddStateBits(NS_ROWGROUP_REPEATABLE); + } else { + RemoveStateBits(NS_ROWGROUP_REPEATABLE); + } +} + +inline bool nsTableRowGroupFrame::HasStyleBSize() const { + return HasAnyStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); +} + +inline void nsTableRowGroupFrame::SetHasStyleBSize(bool aValue) { + if (aValue) { + AddStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); + } else { + RemoveStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); + } +} + +inline void nsTableRowGroupFrame::GetContinuousBCBorderWidth( + mozilla::WritingMode aWM, mozilla::LogicalMargin& aBorder) { + int32_t d2a = PresContext()->AppUnitsPerDevPixel(); + aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a, mIEndContBorderWidth); + aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a, mBEndContBorderWidth); + aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(d2a, mIStartContBorderWidth); +} +#endif |