table frames no longer assume they are n levels below the inner table frame table frames no longer assume their child frames are always the expected type of frame. Now they check the display type and use that as sufficient proof that the frame is of the right type. This implies a heavy reliance on the frame construction code to do the right thing and always stamp out the right kind of frame for a given display type. git-svn-id: svn://10.0.0.236/trunk@10922 18797224-902f-48f8-a5cc-f745e15eee43
499 lines
20 KiB
C++
499 lines
20 KiB
C++
/* -*- 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 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 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.
|
|
* <pre>
|
|
* 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
|
|
* </pre>
|
|
*
|
|
* @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);
|
|
|
|
/** 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);
|
|
|
|
/** 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:<br>
|
|
* calls SetStartColumnIndex on each nsTableColumn<br>
|
|
* sets mSpecifiedColCount.<br>
|
|
*/
|
|
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.<br>
|
|
* otherwise, the content is enumerated and the rows are counted.
|
|
*/
|
|
virtual PRInt32 GetRowCount();
|
|
|
|
/** returns the number of columns in this table. */
|
|
virtual PRInt32 GetColCount();
|
|
|
|
/** adjust the col count for screwy table attributes.
|
|
* currently just handles excess colspan at end of table
|
|
*/
|
|
virtual void SetEffectiveColCount();
|
|
|
|
/** return the column frame at colIndex.
|
|
* returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range
|
|
*/
|
|
nsTableColFrame * GetColFrame(PRInt32 aColIndex);
|
|
|
|
/** return the cell frame at aRowIndex, aColIndex.
|
|
* returns nsnull if the cell frame has not yet been allocated,
|
|
* or if aRowIndex or aColIndex is out of range
|
|
*/
|
|
nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex);
|
|
|
|
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
|
|
* of a row-spanning cell above it.
|
|
* @see nsCellMap::RowIsSpannedInto
|
|
*/
|
|
PRBool RowIsSpannedInto(PRInt32 aRowIndex);
|
|
|
|
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
|
|
* that originate in aRowIndex.
|
|
* @see nsCellMap::RowHasSpanningCells
|
|
*/
|
|
PRBool RowHasSpanningCells(PRInt32 aRowIndex);
|
|
|
|
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
|
|
* of a col-spanning cell.
|
|
* @see nsCellMap::ColIsSpannedInto
|
|
*/
|
|
PRBool ColIsSpannedInto(PRInt32 aColIndex);
|
|
|
|
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
|
|
* @see nsCellMap::ColHasSpanningCells
|
|
*/
|
|
PRBool ColHasSpanningCells(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
|