/* -*- 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 nsReflowState& aReflowState, nsStylePosition *& aPosition) const; /** helper method for getting the width of the table's containing block */ static nscoord GetTableContainerWidth(const nsReflowState& aState); static PRBool TableIsAutoWidth(nsTableFrame *aTableFrame, nsIStyleContext *aTableStyle, const nsReflowState& 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, nsReflowMetrics& aDesiredSize, const nsReflowState& 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, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); /** 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, nsReflowMetrics& aDesiredSize, const nsReflowState& 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). * * @param aMinCaptionWidth - the max of all the minimum caption widths. 0 if no captions. * @param aMaxCaptionWidth - the max of all the desired caption widths. 0 if no captions. * * @see Reflow * @see NeedsReflow */ virtual nsReflowStatus ResizeReflowPass2(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, PRInt32 aMinCaptionWidth, PRInt32 mMaxCaptionWidth); 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 nsReflowState& 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 nsReflowState& 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); /** what stage of reflow is currently in process? */ virtual PRInt32 GetReflowPass() const; /** sets the reflow pass flag. use with caution! */ virtual void SetReflowPass(PRInt32 aReflowPass); /** 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, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); /** Set the min col span for every column in the table. Scans the whole table. */ virtual void SetMinColSpanForTable(); virtual void BuildColumnCache(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& 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:
* calls SetStartColumnIndex on each nsTableColumn
* sets mSpecifiedColCount.
*/ virtual PRInt32 GetSpecifiedColumnCount (); public: /* ----- Cell Map public methods ----- */ /** returns the number of rows in this table. * if mCellMap has been created, it is asked for the number of rows.
* otherwise, the content is enumerated and the rows are counted. */ virtual PRInt32 GetRowCount(); virtual PRInt32 GetColCount(); /** adjust the col count for screwy table attributes. * currently just handles excess colspan at end of table */ virtual void SetEffectiveColCount(); nsTableColFrame * GetColFrame(PRInt32 aColIndex); nsTableCellFrame * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex); private: void DebugPrintCount() const; // Debugging routine /** table reflow is a multi-pass operation. Use these constants to keep track of * which pass is currently being executed. */ enum {kPASS_UNDEFINED=0, kPASS_FIRST=1, kPASS_SECOND=2, kPASS_THIRD=3, kPASS_INCREMENTAL=4}; PRInt32 *mColumnWidths; // widths of each column ColumnInfoCache *mColCache; // cached information about the table columns PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit PRInt32 mPass; // which Reflow pass are we currently in? PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame PRInt32 mColCount; // the number of columns in this table PRInt32 mEffectiveColCount; // the number of columns in this table adjusted for weird table attributes nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells }; #endif