/* -*- 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 TableReflowInput; namespace layers { class StackingContextHelper; } } // namespace mozilla struct BCPropertyData; class nsDisplayTableItem : public nsPaintedDisplayItem { public: nsDisplayTableItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, bool aDrawsBackground = true) : nsPaintedDisplayItem(aBuilder, aFrame), mPartHasFixedBackground(false), mDrawsBackground(aDrawsBackground) {} // 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. virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override; virtual nsDisplayItemGeometry* AllocateGeometry( nsDisplayListBuilder* aBuilder) override; virtual void ComputeInvalidationRegion( nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, nsRegion* aInvalidRegion) const override; void UpdateForFrameBackground(nsIFrame* aFrame); private: bool mPartHasFixedBackground; bool mDrawsBackground; }; class nsDisplayTableBackgroundSet { public: nsDisplayList* ColGroupBackgrounds() { return &mColGroupBackgrounds; } nsDisplayList* ColBackgrounds() { return &mColBackgrounds; } nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable); ~nsDisplayTableBackgroundSet() { mozilla::DebugOnly 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; } 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 mColumns; nsPoint mToReferenceFrame; nsRect mDirtyRect; }; /* ========================================================================== */ 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, kColGroupList, which contains the col group frames. */ class nsTableFrame : public nsContainerFrame { typedef mozilla::image::ImgDrawResult ImgDrawResult; typedef mozilla::WritingMode WritingMode; typedef mozilla::LogicalMargin LogicalMargin; typedef mozilla::TableReflowInput TableReflowInput; public: NS_DECL_FRAMEARENA_HELPERS(nsTableFrame) typedef nsTArray 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 */ virtual void Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) override; static float GetTwipsToPixels(nsPresContext* aPresContext); // 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 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. static void RegisterPositionedTablePart(nsIFrame* aFrame); // Unregister a positioned table part with its nsTableFrame. static void UnregisterPositionedTablePart(nsIFrame* aFrame, nsIFrame* aDestructRoot); nsPoint GetFirstSectionOrigin(const ReflowInput& aReflowInput) const; /* * Notification that rowspan or colspan has changed for content inside a * table cell */ void RowOrColSpanChanged(nsTableCellFrame* aCellFrame); /** @see nsIFrame::DestroyFrom */ virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override; /** @see nsIFrame::DidSetComputedStyle */ virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override; virtual void SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) override; virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override; virtual void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, const nsLineList::iterator* aPrevFrameLine, nsFrameList& aFrameList) override; virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override; virtual nsMargin GetUsedBorder() const override; virtual nsMargin GetUsedPadding() const override; virtual nsMargin GetUsedMargin() const override; // Get the offset from the border box to the area where the row groups fit LogicalMargin GetChildAreaOffset(const WritingMode aWM, const ReflowInput* aReflowInput) const; /** helper method to find the table parent of any table frame object */ static nsTableFrame* GetTableFrame(nsIFrame* aSourceFrame); /* Like GetTableFrame, but will set *aDidPassThrough to false if we don't * pass through aMustPassThrough on the way to the table. */ static nsTableFrame* GetTableFramePassingThrough(nsIFrame* aMustPassThrough, nsIFrame* aSourceFrame, bool* aDidPassThrough); // 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; virtual const nsFrameList& GetChildList(ChildListID aListID) const override; virtual void GetChildLists(nsTArray* aLists) const override; virtual 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; /** * In quirks mode, the size of the table background is reduced * by the outer BC border. Compute the reduction needed. */ nsMargin GetDeflationForBackground(nsPresContext* aPresContext) const; /** Get width of table + colgroup + col collapse: elements that * continue along the length of the whole iStart side. * see nsTablePainter about continuous borders */ nscoord GetContinuousIStartBCBorderWidth() const; void SetContinuousIStartBCBorderWidth(nscoord aValue); 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); virtual void MarkIntrinsicISizesDirty() override; // For border-collapse tables, the caller must not add padding and // border to the results of these functions. virtual nscoord GetMinISize(gfxContext* aRenderingContext) override; virtual 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, mozilla::ComputeSizeFlags aFlags) override; virtual mozilla::LogicalSize ComputeAutoSize( gfxContext* aRenderingContext, mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorderPadding, mozilla::ComputeSizeFlags aFlags) override; /** * A copy of nsIFrame::ShrinkWidthToFit 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. *
   * 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
   * 
* * @see nsIFrame::Reflow */ // clang-format on virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) override; void ReflowTable(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nscoord aAvailBSize, nsIFrame*& aLastChildReflowed, nsReflowStatus& aStatus); nsFrameList& GetColGroups(); virtual ComputedStyle* GetParentComputedStyle( nsIFrame** aProviderFrame) const override; virtual bool IsFrameOfType(uint32_t aFlags) const override { if (aFlags & eSupportsCSSTransforms) { return false; } return nsContainerFrame::IsFrameOfType(aFlags); } #ifdef DEBUG_FRAME_DUMP /** @see nsIFrame::GetFrameName */ virtual 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: virtual nscoord GetLogicalBaseline( mozilla::WritingMode aWritingMode) const override; bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, nscoord* aBaseline) 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); /** empty the column frame cache */ void ClearColCache(); void DidResizeColumns(); void AppendCell(nsTableCellFrame& aCellFrame, int32_t aRowIndex); void InsertCells(nsTArray& aCellFrames, int32_t aRowIndex, int32_t aColIndexBefore); void RemoveCell(nsTableCellFrame* aCellFrame, int32_t aRowIndex); void AppendRows(nsTableRowGroupFrame* aRowGroupFrame, int32_t aRowIndex, nsTArray& aRowFrames); int32_t InsertRows(nsTableRowGroupFrame* aRowGroupFrame, nsTArray& 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& 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); /** destructor, responsible for mColumnLayoutData */ 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 height // to see if it should be made repeatable and also to determine its desired // height. nsresult SetupHeaderFooterChild(const TableReflowInput& aReflowInput, nsTableRowGroupFrame* aFrame, nscoord* aDesiredHeight); void ReflowChildren(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(FirstInFlow())->mTableLayoutStrategy; } // 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); // WIDTH AND HEIGHT CALCULATION public: // calculate the computed block-size of aFrame including its border and // padding given its reflow input. nscoord CalcBorderBoxBSize(const ReflowInput& aReflowInput, const LogicalMargin& aBorderPadding, nscoord aIntrinsicBorderBoxBSize); protected: // update the desired block-size of this table taking into account the // current reflow input, the table attributes and the content driven rowgroup // bsizes this function can change the overflow area void CalcDesiredBSize(const ReflowInput& aReflowInput, ReflowOutput& aDesiredSize); // The following is a helper for CalcDesiredBSize void DistributeBSizeToRows(const ReflowInput& aReflowInput, nscoord aAmount); void PlaceChild(TableReflowInput& aReflowInput, nsIFrame* aKidFrame, const ReflowInput& aKidReflowInput, const mozilla::LogicalPoint& aKidPosition, const nsSize& aContainerSize, ReflowOutput& aKidDesiredSize, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidInkOverflow); void PlaceRepeatedFooter(TableReflowInput& aReflowInput, nsTableRowGroupFrame* aTfoot, nscoord aFooterHeight); nsIFrame* GetFirstBodyRowGroupFrame(); public: typedef AutoTArray RowGroupArray; /** * Push all our child frames from the aRowGroups array, in order, starting * from the frame at aPushFrom to the end of the array. The frames are put on * our overflow list or moved directly to our next-in-flow if one exists. */ protected: void PushChildren(const RowGroupArray& aRowGroups, int32_t aPushFrom); public: // put the children frames in the display order (e.g. thead before tbodies // before tfoot). This will handle calling GetRowGroupFrame() on the // children, and not append nulls, so the array is guaranteed to contain // nsTableRowGroupFrames. If there are multiple theads or tfoots, all but // the first one are treated as tbodies instead. void OrderRowGroups(RowGroupArray& aChildren, 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& GetColCache(); protected: void SetBorderCollapse(bool aValue); BCPropertyData* GetBCProperty() const; BCPropertyData* GetOrCreateBCProperty(); 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& 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(); } public: #ifdef DEBUG void Dump(bool aDumpRows, bool aDumpCols, bool aDumpCellMap); #endif protected: /** * Helper method for RemoveFrame. */ void DoRemoveFrame(ChildListID aListID, nsIFrame* aOldFrame); #ifdef DEBUG void DumpRowGroup(nsIFrame* aChildFrame); #endif // DATA MEMBERS AutoTArray 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 mIStartContBCBorder : 8; 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; } mBits; std::map mDeletedRowIndexRanges; // maintains ranges of row // indices of deleted rows nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, // and cells nsITableLayoutStrategy* mTableLayoutStrategy; // the layout strategy for this // frame 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(FirstInFlow())->mBits.mNeedToCollapse = (unsigned)aValue; } inline bool nsTableFrame::NeedToCollapse() const { return (bool)static_cast(FirstInFlow())->mBits.mNeedToCollapse; } inline nsFrameList& nsTableFrame::GetColGroups() { return static_cast(FirstInFlow())->mColGroups; } inline nsTArray& 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; } inline nscoord nsTableFrame::GetContinuousIStartBCBorderWidth() const { int32_t d2a = PresContext()->AppUnitsPerDevPixel(); return BC_BORDER_END_HALF_COORD(d2a, mBits.mIStartContBCBorder); } inline void nsTableFrame::SetContinuousIStartBCBorderWidth(nscoord aValue) { mBits.mIStartContBCBorder = (unsigned)aValue; } #define ABORT0() \ { \ NS_ASSERTION(false, "CellIterator program error"); \ return; \ } #define ABORT1(aReturn) \ { \ NS_ASSERTION(false, "CellIterator program error"); \ return aReturn; \ } #endif