/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef nsTableFrame_h__ #define nsTableFrame_h__ #include "nscore.h" #include "nsVoidArray.h" #include "nsHTMLContainerFrame.h" #include "nsStyleCoord.h" #include "nsStyleConsts.h" #include "nsITableLayout.h" #include "nsTableColFrame.h" #include "nsTableColGroupFrame.h" #include "nsCellMap.h" #include "nsGkAtoms.h" #include "nsDisplayList.h" class nsTableCellFrame; class nsTableColFrame; class nsTableRowGroupFrame; class nsTableRowFrame; class nsTableColGroupFrame; class nsITableLayoutStrategy; class nsStyleContext; struct nsTableReflowState; struct nsStylePosition; /** * Child list name indices * @see #GetAdditionalChildListName() */ #define NS_TABLE_FRAME_COLGROUP_LIST_INDEX 0 #define NS_TABLE_FRAME_OVERFLOW_LIST_INDEX 1 #define NS_TABLE_FRAME_LAST_LIST_INDEX NS_TABLE_FRAME_OVERFLOW_LIST_INDEX static inline PRBool IS_TABLE_CELL(nsIAtom* frameType) { return nsGkAtoms::tableCellFrame == frameType || nsGkAtoms::bcTableCellFrame == frameType; } class nsDisplayTableItem : public nsDisplayItem { public: nsDisplayTableItem(nsIFrame* aFrame) : nsDisplayItem(aFrame), mPartHasFixedBackground(PR_FALSE) {} virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder); // 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); void UpdateForFrameBackground(nsIFrame* aFrame); private: PRPackedBool mPartHasFixedBackground; }; class nsAutoPushCurrentTableItem { public: nsAutoPushCurrentTableItem() : mBuilder(nsnull) {} void Push(nsDisplayListBuilder* aBuilder, nsDisplayTableItem* aPushItem) { mBuilder = aBuilder; mOldCurrentItem = aBuilder->GetCurrentTableItem(); aBuilder->SetCurrentTableItem(aPushItem); #ifdef DEBUG mPushedItem = aPushItem; #endif } ~nsAutoPushCurrentTableItem() { if (!mBuilder) return; #ifdef DEBUG NS_ASSERTION(mBuilder->GetCurrentTableItem() == mPushedItem, "Someone messed with the current table item behind our back!"); #endif mBuilder->SetCurrentTableItem(mOldCurrentItem); } private: nsDisplayListBuilder* mBuilder; nsDisplayTableItem* mOldCurrentItem; #ifdef DEBUG nsDisplayTableItem* mPushedItem; #endif }; /* ============================================================================ */ /** nsTableFrame maps the inner portion of a table (everything except captions.) * Used as a pseudo-frame within nsTableOuterFrame, it may also be used * stand-alone as the top-level frame. * * The flowed child list contains row group frames. There is also an additional * named child list: * - "ColGroup-list" which contains the col group frames * * @see nsGkAtoms::colGroupList */ class nsTableFrame : public nsHTMLContainerFrame, public nsITableLayout { public: // nsISupports NS_DECL_ISUPPORTS_INHERITED /** nsTableOuterFrame has intimate knowledge of the inner table frame */ friend class nsTableOuterFrame; /** instantiate a new instance of nsTableRowFrame. * @param aPresShell the pres shell for this frame * * @return the frame that was created */ friend nsIFrame* NS_NewTableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); /** sets defaults for table-specific style. * @see nsIFrame::Init */ NS_IMETHOD Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow); static void* GetProperty(nsIFrame* aFrame, nsIAtom* aPropertyName, PRBool aCreateIfNecessary = PR_FALSE); static float GetTwipsToPixels(nsPresContext* aPresContext); // Return true if aParentReflowState.frame or any of its ancestors within // the containing table have non-auto height. (e.g. pct or fixed height) static PRBool AncestorsHaveStyleHeight(const nsHTMLReflowState& aParentReflowState); // See if a special height reflow will occur due to having a pct height when // the pct height basis may not yet be valid. static void CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState); // Notify the frame and its ancestors (up to the containing table) that a special // height reflow will occur. static void RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState); virtual PRBool IsContainingBlock() const; static void RePositionViews(nsIFrame* aFrame); static PRBool PageBreakAfter(nsIFrame& aSourceFrame, nsIFrame* aNextFrame); nsPoint GetFirstSectionOrigin(const nsHTMLReflowState& aReflowState) const; /* * Notification that aAttribute has changed for content inside a table (cell, row, etc) */ void AttributeChangedFor(nsIFrame* aFrame, nsIContent* aContent, nsIAtom* aAttribute); /** @see nsIFrame::Destroy */ virtual void Destroy(); NS_IMETHOD AppendFrames(nsIAtom* aListName, nsIFrame* aFrameList); NS_IMETHOD InsertFrames(nsIAtom* aListName, nsIFrame* aPrevFrame, nsIFrame* aFrameList); NS_IMETHOD RemoveFrame(nsIAtom* aListName, nsIFrame* aOldFrame); virtual nsMargin GetUsedBorder() const; virtual nsMargin GetUsedPadding() const; // Get the offset from the border box to the area where the row groups fit nsMargin GetChildAreaOffset(const nsHTMLReflowState* aReflowState) const; // Get the offset from the border box to the area where the content fits nsMargin GetContentAreaOffset(const nsHTMLReflowState* aReflowState) const; /** helper method to find the table parent of any table frame object */ static nsTableFrame* GetTableFrame(nsIFrame* aSourceFrame); typedef nsresult (* DisplayGenericTablePartTraversal) (nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); static nsresult GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); /** * Helper method to handle display common to table frames, rowgroup frames * and row frames. It creates a background display item for handling events * if necessary, an outline display item if necessary, and displays * all the the frame's children. * @param aDisplayItem the display item created for this part, or null * if this part's border/background painting is delegated to an ancestor * @param aTraversal a function that gets called to traverse the table * part's child frames and add their display list items to a * display list set. */ static nsresult DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, nsDisplayTableItem* aDisplayItem, DisplayGenericTablePartTraversal aTraversal = GenericTraversal); // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. static nsIFrame* GetFrameAtOrBefore(nsIFrame* aParentFrame, nsIFrame* aPriorChildFrame, nsIAtom* aChildType); PRBool IsAutoWidth(PRBool* aIsPctWidth = nsnull); PRBool IsAutoHeight(); static PRBool IsPctHeight(nsStyleContext* aStyleContext); /** @return PR_TRUE if aDisplayType represents a rowgroup of any sort * (header, footer, or body) */ PRBool IsRowGroup(PRInt32 aDisplayType) const; /** Initialize the table frame with a set of children. * @see nsIFrame::SetInitialChildList */ NS_IMETHOD SetInitialChildList(nsIAtom* aListName, nsIFrame* aChildList); /** return the first child belonging to the list aListName. * @see nsIFrame::GetFirstChild */ virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const; /** @see nsIFrame::GetAdditionalChildListName */ virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const; NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); /** * Paint the background of the table and its parts (column groups, * columns, row groups, rows, and cells), and the table border, and all * internal borders if border-collapse is on. */ void PaintTableBorderBackground(nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt); // 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. nsMargin GetOuterBCBorder() const; // Same as above, but only if it's included from the border-box width // of the table (nonzero only in quirks mode). nsMargin GetIncludedOuterBCBorder() const; // Same as above, but only if it's excluded from the border-box width // of the table (nonzero only in standards mode). This is the area // that leaks out into the margin (or potentially past it, if there is // no margin). nsMargin GetExcludedOuterBCBorder() const; /** Get width of table + colgroup + col collapse: elements that * continue along the length of the whole left side. * see nsTablePainter about continuous borders * @param aPixelsToTwips - conversion factor * @param aGetInner - get only inner half of border width */ nscoord GetContinuousLeftBCBorderWidth() const; void SetBCDamageArea(const nsRect& aValue); void PaintBCBorders(nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); /** nsIFrame method overridden to handle table specifics */ NS_IMETHOD SetSelected(nsPresContext* aPresContext, nsIDOMRange *aRange, PRBool aSelected, nsSpread aSpread); virtual void MarkIntrinsicWidthsDirty(); // For border-collapse tables, the caller must not add padding and // border to the results of these functions. virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); virtual IntrinsicWidthOffsetData IntrinsicWidthOffsets(nsIRenderingContext* aRenderingContext); virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext, nsSize aCBSize, nscoord aAvailableWidth, nsSize aMargin, nsSize aBorder, nsSize aPadding, PRBool aShrinkWrap); virtual nsSize ComputeAutoSize(nsIRenderingContext *aRenderingContext, nsSize aCBSize, nscoord aAvailableWidth, nsSize aMargin, nsSize aBorder, nsSize aPadding, PRBool aShrinkWrap); /** * A copy of nsFrame::ShrinkWidthToFit that calls a different * GetPrefWidth, since tables have two different ones. */ nscoord TableShrinkWidthToFit(nsIRenderingContext *aRenderingContext, nscoord aWidthInCB); // XXXldb REWRITE THIS COMMENT! /** 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 */ NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); nsresult ReflowTable(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nscoord aAvailHeight, nsIFrame*& aLastChildReflowed, nsReflowStatus& aStatus); nsFrameList& GetColGroups(); NS_IMETHOD GetParentStyleContextFrame(nsPresContext* aPresContext, nsIFrame** aProviderFrame, PRBool* aIsChild); /** * Get the "type" of the frame * * @see nsGkAtoms::tableFrame */ virtual nsIAtom* GetType() const; #ifdef DEBUG /** @see nsIFrame::GetFrameName */ NS_IMETHOD GetFrameName(nsAString& aResult) const; #endif /** return the width of the column at aColIndex */ virtual PRInt32 GetColumnWidth(PRInt32 aColIndex); /** set the width of the column at aColIndex to aWidth */ virtual void SetColumnWidth(PRInt32 aColIndex, nscoord aWidth); /** helper to get the cell spacing X style value */ virtual nscoord GetCellSpacingX(); /** helper to get the cell spacing Y style value */ virtual nscoord GetCellSpacingY(); virtual nscoord GetBaseline() const; /** 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. */ virtual PRInt32 GetEffectiveRowSpan(PRInt32 aStartRowIndex, const nsTableCellFrame& aCell) const; virtual PRInt32 GetEffectiveRowSpan(const nsTableCellFrame& aCell, nsCellMap* aCellMap = nsnull); /** 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. */ virtual PRInt32 GetEffectiveColSpan(const nsTableCellFrame& aCell, nsCellMap* aCellMap = nsnull) const; /** indicate whether the row has more than one cell that either originates * or is spanned from the rows above */ PRBool HasMoreThanOneCell(PRInt32 aRowIndex) const; /** return the value of the COLS attribute, adjusted for the * actual number of columns in the table */ PRInt32 GetEffectiveCOLSAttribute(); /** return the column frame associated with aColIndex * returns nsnull if the col frame has not yet been allocated, or if * aColIndex is out of range */ nsTableColFrame* GetColFrame(PRInt32 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, PRInt32 aColIndex); nsTableColGroupFrame* CreateAnonymousColGroupFrame(nsTableColGroupType aType); PRInt32 DestroyAnonymousColFrames(PRInt32 aNumFrames); void CreateAnonymousColFrames(PRInt32 aNumColsToAdd, nsTableColType aColType, PRBool aDoAppend, nsIFrame* aPrevCol = nsnull); void CreateAnonymousColFrames(nsTableColGroupFrame* aColGroupFrame, PRInt32 aNumColsToAdd, nsTableColType aColType, PRBool aAddToColGroupAndTable, nsIFrame* aPrevCol, nsIFrame** aFirstNewFrame); void MatchCellMapToColCache(nsTableCellMap* aCellMap); /** empty the column frame cache */ void ClearColCache(); void DidResizeColumns(); virtual void AppendCell(nsTableCellFrame& aCellFrame, PRInt32 aRowIndex); virtual void InsertCells(nsVoidArray& aCellFrames, PRInt32 aRowIndex, PRInt32 aColIndexBefore); virtual void RemoveCell(nsTableCellFrame* aCellFrame, PRInt32 aRowIndex); void AppendRows(nsTableRowGroupFrame& aRowGroupFrame, PRInt32 aRowIndex, nsVoidArray& aRowFrames); PRInt32 InsertRow(nsTableRowGroupFrame& aRowGroupFrame, nsIFrame& aFrame, PRInt32 aRowIndex, PRBool aConsiderSpans); PRInt32 InsertRows(nsTableRowGroupFrame& aRowGroupFrame, nsVoidArray& aFrames, PRInt32 aRowIndex, PRBool aConsiderSpans); virtual void RemoveRows(nsTableRowFrame& aFirstRowFrame, PRInt32 aNumRowsToRemove, PRBool aConsiderSpans); /** Insert multiple rowgroups into the table cellmap handling * @param aFirstRowGroupFrame - first row group to be inserted all siblings * will be appended too. */ void AppendRowGroups(nsIFrame* aFirstRowGroupFrame); /** Insert multiple rowgroups into the table cellmap handling * @param aFirstRowGroupFrame - first row group to be inserted * @param aLastRowGroupFrame - when inserting the siblings of * aFirstRowGroupFrame stop at this row group */ void InsertRowGroups(nsIFrame* aFirstRowGroupFrame, nsIFrame* aLastRowGroupFrame); void InsertColGroups(PRInt32 aColIndex, nsIFrame* aFirstFrame, nsIFrame* aLastFrame = nsnull); virtual void RemoveCol(nsTableColGroupFrame* aColGroupFrame, PRInt32 aColIndex, PRBool aRemoveFromCache, PRBool aRemoveFromCellMap); NS_IMETHOD GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn, PRInt32 *aIndex); NS_IMETHOD GetRowAndColumnByIndex(PRInt32 aIndex, PRInt32 *aRow, PRInt32 *aColumn); PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const; PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const; PRBool HasPctCol() const; void SetHasPctCol(PRBool aValue); PRBool HasCellSpanningPctCol() const; void SetHasCellSpanningPctCol(PRBool 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 reflown 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 aOrigOverflowRect The original overflow rect of aFrame. * @param aIsFirstReflow True if the size/position change is due to the * first reflow of aFrame. */ static void InvalidateFrame(nsIFrame* aFrame, const nsRect& aOrigRect, const nsRect& aOrigOverflowRect, PRBool aIsFirstReflow); protected: /** protected constructor. * @see NewFrame */ nsTableFrame(nsStyleContext* aContext); /** destructor, responsible for mColumnLayoutData */ virtual ~nsTableFrame(); void InitChildReflowState(nsHTMLReflowState& aReflowState); /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; virtual PRBool ParentDisablesSelection() const; //override default behavior public: PRBool IsRowInserted() const; void SetRowInserted(PRBool 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 nsTableReflowState& aReflowState, nsTableRowGroupFrame* aFrame, nscoord* aDesiredHeight); NS_METHOD ReflowChildren(nsTableReflowState& aReflowState, nsReflowStatus& aStatus, nsIFrame*& aLastChildReflowed, nsRect& aOverflowArea); // 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(nsIRenderingContext* aRenderingContext); /** return the width of the table taking into account visibility collapse * on columns and colgroups * @param aBorderPadding the border and padding of the table */ nscoord GetCollapsedWidth(nsMargin aBorderPadding); /** Adjust the table for visibilty.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(nsHTMLReflowMetrics& aDesiredSize, nsMargin aBorderPadding); nsITableLayoutStrategy* LayoutStrategy() { return static_cast