/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #ifndef nsTableFrame_h__ #define nsTableFrame_h__ #include "nscore.h" #include "nsContainerFrame.h" #include "nsStyleCoord.h" class nsCellMap; class nsVoidArray; class nsTableCellFrame; class nsTableColFrame; class nsTableRowGroupFrame; class nsTableRowFrame; class nsITableLayoutStrategy; class nsHTMLValue; class ColumnInfoCache; struct InnerTableReflowState; struct nsStylePosition; struct nsStyleSpacing; /* ff1d2780-06d6-11d2-8f37-006008159b0c */ #define NS_TABLEFRAME_CID \ {0xff1d2780, 0x06d6, 0x11d2, {0x8f, 0x37, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x0c}} extern const nsIID kTableFrameCID; /* ============================================================================ */ /** 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 meaningful child frames of nsTableFrame map rowgroups. * * @author sclark * * TODO: make methods virtual so nsTableFrame can be used as a base class in the future. */ class nsTableFrame : public nsContainerFrame { public: /** nsTableOuterFrame has intimate knowledge of the inner table frame */ friend class nsTableOuterFrame; /** instantiate a new instance of nsTableFrame. * @param aResult the new object is returned in this out-param * @param aContent the table object to map * @param aParent the parent of the new frame * * @return NS_OK if the frame was properly allocated, otherwise an error code */ friend nsresult NS_NewTableFrame(nsIContent* aContent, nsIFrame* aParentFrame, nsIFrame*& aResult); // nsISupports NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); /** helper method for determining if this is a nested table or not */ PRBool IsNested(const nsHTMLReflowState& aReflowState, nsStylePosition *& aPosition) const; /** helper method to find the table parent of any table frame object */ static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aOutFrame); /** helper method for getting the width of the table's containing block */ static nscoord GetTableContainerWidth(const nsHTMLReflowState& aState); static PRBool TableIsAutoWidth(nsTableFrame *aTableFrame, nsIStyleContext *aTableStyle, const nsHTMLReflowState& aReflowState, nscoord& aSpecifiedTableWidth); NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); /** @see nsIFrame::Paint */ NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); /** 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 ResizeReflowPass1
* @see ResizeReflowPass2
* @see BalanceColumnWidths
* @see nsIFrame::Reflow
*/
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
/** @see nsContainerFrame::CreateContinuingFrame */
NS_IMETHOD CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,
nsIStyleContext* aStyleContext,
nsIFrame*& aContinuingFrame);
/** allow the cell and row attributes to effect the column frame
* currently, the only reason this exists is to support the HTML "rule"
* that a width attribute on a cell in the first column sets the column width.
*/
virtual NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext,
nsTableCellFrame* aCellFrame,
nsTableRowFrame * aRowFrame);
/** the COLS attribute can be modified by any cell's width attribute.
* deal with it here. Must be called before any call to
* ColumnInfoCache::AddColumnInfo
*/
virtual void AdjustColumnsForCOLSAttribute();
/** return the column frame corresponding to the given column index
* there are two ways to do this, depending on whether we have cached
* column information yet.
*/
NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame);
/**
* DEBUG METHOD
*
*/
//virtual void ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const;
/** 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 style value */
virtual nscoord GetCellSpacing();
/**
* Calculate Layout Information
*
*/
void AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell);
void RecalcLayoutData();
// Get cell margin information
NS_IMETHOD GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin);
/** get cached column information for a subset of the columns
*
* @param aType -- information is returned for the subset of columns with aType style
* @param aOutNumColumns -- out param, the number of columns matching aType
* @param aOutColumnIndexes -- out param, the indexes of the columns matching aType
*
* TODO : make aOutColumnIndexes safe
*/
void GetColumnsByType(const nsStyleUnit aType,
PRInt32& aOutNumColumns,
PRInt32 *& aOutColumnIndexes);
/** return the row span of a cell, taking into account row span magic at the bottom
* of a table.
*
* @param aRowIndex the row from which to measure effective row span
* @param aCell the cell
*
* @return the row span, correcting for row spans that extend beyond the bottom
* of the table.
*/
virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell);
/** return the col span of a cell, taking into account col span magic at the edge
* of a table.
*
* @param aColIndex the column from which to measure effective col span
* @param aCell the cell
*
* @return the col span, correcting for col spans that extend beyond the edge
* of the table.
*/
virtual PRInt32 GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame *aCell);
/** return the value of the COLS attribute, adjusted for the
* actual number of columns in the table
*/
PRInt32 GetEffectiveCOLSAttribute();
/** verify that there are at least aColIndex column frames created.
* if not, create the needed col frames
*/
virtual void EnsureColumnFrameAt(PRInt32 aColIndex,
nsIPresContext* aPresContext);
/** return the index of the next row that is not yet assigned.
* If no row is initialized, 0 is returned.
*/
PRInt32 GetNextAvailRowIndex() const;
/** return the index of the next column in aRowIndex after aColIndex
* that does not have a cell assigned to it.
* If aColIndex is past the end of the row, it is returned.
* If the row is not initialized, 0 is returned.
*/
PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
/** build as much of the CellMap as possible from the info we have so far
*/
virtual void AddCellToTable (nsTableRowFrame *aRowFrame,
nsTableCellFrame *aCellFrame,
PRBool aAddRow);
virtual void AddColumnFrame (nsTableColFrame *aColFrame);
NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0, nsIListFilter *aFilter = nsnull) const;
protected:
/** protected constructor.
* @see NewFrame
*/
nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame);
/** destructor, responsible for mColumnLayoutData and mColumnWidths */
virtual ~nsTableFrame();
/** first pass of ResizeReflow.
* lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and
* a non-null aMaxElementSize so we get all the metrics we need to do column balancing.
* Pass 1 only needs to be executed once no matter how many times the table is resized,
* as long as content and style don't change. This is managed in the member variable mFirstPassIsValid.
* The layout information for each cell is cached in mColumLayoutData.
*
* @see Reflow
*/
virtual nsReflowStatus ResizeReflowPass1(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
/** second pass of ResizeReflow.
* lays out all table content with aMaxSize(computed_table_width, given_table_height)
* Pass 2 is executed every time the table needs to resize. An optimization is included
* so that if the table doesn't need to actually be resized, no work is done (see NeedsReflow).
*
*
* @see Reflow
* @see NeedsReflow
*/
virtual nsReflowStatus ResizeReflowPass2(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState);
nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext,
InnerTableReflowState& aState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
/** return the desired width of this table accounting for the current
* reflow state, and for the table attributes and parent
*/
nscoord ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) const;
nscoord GetTopMarginFor(nsIPresContext* aCX,
InnerTableReflowState& aState,
const nsMargin& aKidMargin);
void PlaceChild(nsIPresContext* aPresContext,
InnerTableReflowState& aState,
nsIFrame* aKidFrame,
const nsRect& aKidRect,
nsSize* aMaxElementSize,
nsSize& aKidMaxElementSize);
/**
* Reflow the frames we've already created
*
* @param aPresContext presentation context to use
* @param aState current inline state
* @return true if we successfully reflowed all the mapped children and false
* otherwise, e.g. we pushed children to the next in flow
*/
PRBool ReflowMappedChildren(nsIPresContext* aPresContext,
InnerTableReflowState& aState,
nsSize* aMaxElementSize);
/**
* Try and pull-up frames from our next-in-flow
*
* @param aPresContext presentation context to use
* @param aState current inline state
* @return true if we successfully pulled-up all the children and false
* otherwise, e.g. child didn't fit
*/
PRBool PullUpChildren(nsIPresContext* aPresContext,
InnerTableReflowState& aState,
nsSize* aMaxElementSize);
/** assign widths for each column, taking into account the table content, the effective style,
* the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect.
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aMaxSize the height and width constraints
* @param aMaxElementSize the min size of the largest indivisible object
*/
virtual void BalanceColumnWidths(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
const nsSize& aMaxSize,
nsSize* aMaxElementSize);
/** sets the width of the table according to the computed widths of each column. */
virtual void SetTableWidth(nsIPresContext* aPresContext);
/**
*/
virtual void VerticallyAlignChildren(nsIPresContext* aPresContext,
nscoord* aAscents,
nscoord aMaxAscent,
nscoord aMaxHeight);
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsSize& aMaxSize);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsFirstPassValid() const;
/** do post processing to setting up style information for the frame */
NS_IMETHOD DidSetStyleContext(nsIPresContext* aPresContext);
/** Support methods for DidSetStyleContext */
void MapBorderMarginPadding(nsIPresContext* aPresContext);
void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth);
PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult);
/** called whenever the number of columns changes, to increase the storage in mCellMap
*/
virtual void GrowCellMap(PRInt32 aColCount);
/** ResetCellMap is called when the cell structure of the table is changed.
* Call with caution, only when changing the structure of the table such as
* inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc.
*/
virtual void ResetCellMap ();
/** Get the cell map for this table frame. It is not always mCellMap.
* Only the firstInFlow has a legit cell map
*/
virtual nsCellMap *GetCellMap();
/** for debugging only
* prints out information about the cell map
*/
void DumpCellMap();
/** for debugging only
* prints out info about the table layout state, printing columns and their cells
*/
void ListColumnLayoutData(FILE* out, PRInt32 aIndent);
/** sum the columns represented by all nsTableColGroup objects.
* if the cell map says there are more columns than this,
* add extra implicit columns to the content tree.
*/
virtual void EnsureColumns (nsIPresContext* aPresContext);
/** Set the min col span for every column in the table. Scans the whole table. */
virtual void SetMinColSpanForTable();
virtual void BuildColumnCache(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
/** called every time we discover we have a new cell to add to the table.
* This could be because we got actual cell content, because of rowspan/colspan attributes, etc.
* This method changes mCellMap as necessary to account for the new cell.
*
* @param aCell the content object created for the cell
* @param aRowIndex the row into which the cell is to be inserted
* @param aColIndex the col into which the cell is to be inserted
*/
virtual void BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex);
/** returns the index of the first child after aStartIndex that is a row group
*/
virtual nsTableRowGroupFrame* NextRowGroupFrame (nsTableRowGroupFrame*);
/** return the number of columns as specified by the input.
* has 2 side effects: