/* -*- 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" class nsCellMap; class nsTableCellMap; class nsTableCellFrame; class nsTableColFrame; class nsTableRowGroupFrame; class nsTableRowFrame; class nsTableColGroupFrame; class nsITableLayoutStrategy; class nsStyleContext; struct nsTableReflowState; struct nsStylePosition; enum nsPixelRound {eAlwaysRoundUp=0, eAlwaysRoundDown, eRoundUpIfHalfOrMore}; #ifdef DEBUG_TABLE_REFLOW_TIMING #ifdef WIN32 #include #endif class nsReflowTimer { public: nsReflowTimer(nsIFrame* aFrame) { mFrame = aFrame; mNextSibling = nsnull; mFrameType = aFrame->GetType(); NS_IF_ADDREF(mFrameType); mReflowType = -1; Reset(); } void Destroy() { PRInt32 numChildren = mChildren.Count(); for (PRInt32 childX = 0; childX < numChildren; childX++) { ((nsReflowTimer*)mChildren.ElementAt(childX))->Destroy(); } NS_IF_RELEASE(mFrameType); if (mNextSibling) { // table frames have 3 auxillary timers delete mNextSibling->mNextSibling->mNextSibling; delete mNextSibling->mNextSibling; delete mNextSibling; } delete this; } void Print(PRUint32 aIndent, char* aHeader = 0) { if (aHeader) { printf("%s", aHeader); } printf(" elapsed=%d numStarts=%d \n", Elapsed(), mNumStarts); } PRUint32 Elapsed() { return mTotalTime; } void Reset() { mTotalTime = mNumStarts = 0; mStarted = PR_FALSE; } void Start() { NS_ASSERTION(!mStarted, "started timer without stopping"); #ifdef WIN32 mStartTime = GetTickCount(); #else mStartTime = 0; #endif mStarted = PR_TRUE; mNumStarts++; } void Stop() { NS_ASSERTION(mStarted, "stopped timer without starting"); mTotalTime += GetTickCount() - mStartTime; mStarted = PR_FALSE; } PRUint32 mTotalTime; PRUint32 mStartTime; PRUint32 mNumStarts; PRBool mStarted; const nsIFrame* mFrame; nsIAtom* mFrameType; // needed for frame summary timer nsReflowReason mReason; nsVoidArray mChildren; PRInt32 mCount; // reflow state/reflow metrics data nscoord mAvailWidth; nscoord mComputedWidth; nscoord mComputedHeight; nscoord mMaxElementWidth; nscoord mMaxWidth; // preferred width nscoord mDesiredWidth; nscoord mDesiredHeight; nsReflowStatus mStatus; nsReflowTimer* mNextSibling; PRInt32 mReflowType; private: ~nsReflowTimer() {} }; #endif /** * 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 /* ============================================================================ */ /** 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 nsLayoutAtoms::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 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(nsIPresShell* aPresShell, nsIFrame** aResult); /** sets defaults for table-specific style. * @see nsIFrame::Init */ NS_IMETHOD Init(nsPresContext* aPresContext, nsIContent* aContent, nsIFrame* aParent, nsStyleContext* aContext, nsIFrame* aPrevInFlow); static void* GetProperty(nsIFrame* aFrame, nsIAtom* aPropertyName, PRBool aCreateIfNecessary = PR_FALSE); static float GetTwipsToPixels(nsPresContext* aPresContext); static nscoord RoundToPixel(nscoord aValue, float aPixelToTwips, nsPixelRound aRound= eAlwaysRoundUp); // 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); // Return true (and set aMetrics's desiredSize to aRect) if the special height reflow // was not initiated by aReflowState.frame's containing table. static PRBool IsPrematureSpecialHeightReflow(const nsHTMLReflowState& aReflowState, const nsRect& aRect, PRBool aNeedSpecialHeightReflow, nsHTMLReflowMetrics& aMetrics); virtual PRBool IsContainingBlock() const; static nsresult AppendDirtyReflowCommand(nsIFrame* aFrame); 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 */ NS_IMETHOD Destroy(nsPresContext* aPresContext); NS_IMETHOD AppendFrames(nsIAtom* aListName, nsIFrame* aFrameList); NS_IMETHOD InsertFrames(nsIAtom* aListName, nsIFrame* aPrevFrame, nsIFrame* aFrameList); NS_IMETHOD RemoveFrame(nsIAtom* aListName, nsIFrame* aOldFrame); // 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 */ // TODO: today, this depends on display types. This should be changed to rely // on stronger criteria, like an inner table frame atom static NS_METHOD GetTableFrame(nsIFrame* aSourceFrame, nsTableFrame*& aTableFrame); // 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(nsPresContext* aPresContext, 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; /** @see nsIFrame::Paint */ NS_IMETHOD Paint(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); virtual void PaintChildren(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); nsMargin GetBCBorder() const; // get the area that the border leak out from the inner table frame into // the surrounding margin space nsMargin GetBCMargin() 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(float aPixelsToTwips) const; void SetBCDamageArea(const nsRect& aValue); void PaintBCBorders(nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); NS_IMETHOD GetFrameForPoint(const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, nsIFrame** aFrame); /** nsIFrame method overridden to handle table specifics */ NS_IMETHOD SetSelected(nsPresContext* aPresContext, nsIDOMRange *aRange, PRBool aSelected, nsSpread aSpread); /** 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 nsIFrameReflow::Reflow */ NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); nsresult ReflowTable(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nscoord aAvailHeight, nsReflowReason aReason, nsIFrame*& aLastChildReflowed, PRBool& aDidBalance, nsReflowStatus& aStatus); static nsMargin GetBorderPadding(const nsHTMLReflowState& aReflowState, float aPixelToTwips, const nsTableCellFrame* aCellFrame); static nsMargin GetBorderPadding(const nsSize& aBasis, float aPixelToTwips, const nsTableCellFrame* aCellFrame); nsFrameList& GetColGroups(); NS_IMETHOD GetParentStyleContextFrame(nsPresContext* aPresContext, nsIFrame** aProviderFrame, PRBool* aIsChild); /** * Get the "type" of the frame * * @see nsLayoutAtoms::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(); /** 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(); 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); nsTableCellFrame* GetCellInfoAt(PRInt32 aRowX, PRInt32 aColX, PRBool* aOriginates = nsnull, PRInt32* aColSpan = nsnull); PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const; PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const; PRBool HasPctCol() const; void SetHasPctCol(PRBool aValue); PRBool HasCellSpanningPctCol() const; void SetHasCellSpanningPctCol(PRBool aValue); PRBool NeedSpecialReflow() const; void SetNeedSpecialReflow(PRBool aValue); PRBool NeedToInitiateSpecialReflow() const; void SetNeedToInitiateSpecialReflow(PRBool aValue); PRBool InitiatedSpecialReflow() const; void SetInitiatedSpecialReflow(PRBool aValue); protected: /** protected constructor. * @see NewFrame */ nsTableFrame(); /** 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: /** first pass of ResizeReflow. * lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and * a true mComputeMEW 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. * Incremental layout can take advantage of aStartingFrame to pick up where a previous * ResizeReflowPass1 left off. * * @see nsIFrameReflow::Reflow */ /** do I need to do a reflow? */ virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState); PRBool IsRowInserted() const; void SetRowInserted(PRBool aValue); protected: NS_METHOD ReflowChildren(nsTableReflowState& aReflowState, PRBool aDoColGroups, PRBool aDirtyOnly, nsReflowStatus& aStatus, nsIFrame*& aLastChildReflowed, nsRect& aOverflowArea, PRBool* aReflowedAtLeastOne = nsnull); // begin incremental reflow methods /** Incremental Reflow attempts to do column balancing with the minimum number of reflow * commands to child elements. This is done by processing the reflow command, * rebalancing column widths (if necessary), then comparing the resulting column widths * to the prior column widths and reflowing only those cells that require a reflow. * All incremental reflows go through this method. * * @see Reflow */ NS_IMETHOD IncrementalReflow(const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); /** process an incremental reflow command targeted at a child of this frame. * @param aNextFrame the next frame in the reflow target chain * @see nsIFrameReflow::Reflow */ NS_IMETHOD IR_TargetIsChild(nsTableReflowState& aReflowStatet, nsReflowStatus& aStatus, nsIFrame* aNextFrame); /** process an incremental reflow command targeted at this frame. * @see nsIFrameReflow::Reflow */ NS_IMETHOD IR_TargetIsMe(nsTableReflowState& aReflowState, nsReflowStatus& aStatus); /** process a style changed notification. * @see nsIFrameReflow::Reflow * TODO: needs to be optimized for which attribute was actually changed. */ NS_IMETHOD IR_StyleChanged(nsTableReflowState& aReflowState, nsReflowStatus& aStatus); NS_IMETHOD AdjustSiblingsAfterReflow(nsTableReflowState& aReflowState, nsIFrame* aKidFrame, nscoord aDeltaY); nsresult RecoverState(nsTableReflowState& aReflowState, nsIFrame* aKidFrame); NS_METHOD CollapseRowGroupIfNecessary(nsIFrame* aRowGroupFrame, const nscoord& aYTotalOffset, nscoord& aYGroupOffset, PRInt32& aRowX); NS_METHOD AdjustForCollapsingRows(nsHTMLReflowMetrics& aDesiredSize); NS_METHOD AdjustForCollapsingCols(nsHTMLReflowMetrics& aDesiredSize); // end incremental reflow methods // WIDTH AND HEIGHT CALCULATION public: // calculate the computed width of aFrame including its border and padding given // its reflow state. nscoord CalcBorderBoxWidth(const nsHTMLReflowState& aReflowState); // calculate the computed height of aFrame including its border and padding given // its reflow state. nscoord CalcBorderBoxHeight(const nsHTMLReflowState& aReflowState); // calculate the minimum width to layout aFrame and its desired width // including border and padding given its reflow state and column width information void CalcMinAndPreferredWidths(const nsHTMLReflowState& aReflowState, PRBool aCalcPrefWidthIfAutoWithPctCol, nscoord& aMinWidth, nscoord& aPreferredWidth); protected: // calcs the width of the table according to the computed widths of each column. virtual PRInt32 CalcDesiredWidth(const nsHTMLReflowState& aReflowState); // update the desired height of this table taking into account the current // reflow state, the table attributes and the content driven rowgroup heights // this function can change the overflow area void CalcDesiredHeight(const nsHTMLReflowState& aReflowState, nsHTMLReflowMetrics& aDesiredSize); // The following is a helper for CalcDesiredHeight void DistributeHeightToRows(const nsHTMLReflowState& aReflowState, nscoord aAmount); void PlaceChild(nsTableReflowState& aReflowState, nsIFrame* aKidFrame, nsHTMLReflowMetrics& aKidDesiredSize); /** assign widths for each column, taking into account the table content, the effective style, * the layout constraints, and the compatibility mode. * @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(const nsHTMLReflowState& aReflowState); nsIFrame* GetFirstBodyRowGroupFrame(); PRBool MoveOverflowToChildList(nsPresContext* aPresContext); /** * Push all our child frames from the aFrames 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. */ void PushChildren(const nsAutoVoidArray& aFrames, PRInt32 aPushFrom); public: // put the children frames in the display order (e.g. thead before tbody before tfoot) // and put the non row group frames at the end. Also return the number of row group frames. void OrderRowGroups(nsVoidArray& aChildren, PRUint32& aNumRowGroups, nsIFrame** aFirstBody = nsnull, nsTableRowGroupFrame** aHead = nsnull, nsTableRowGroupFrame** aFoot = nsnull) const; // Returns PR_TRUE if there are any cells above the row at // aRowIndex and spanning into the row at aRowIndex PRBool RowIsSpannedInto(PRInt32 aRowIndex); // Returns PR_TRUE if there is a cell originating in aRowIndex // which spans into the next row PRBool RowHasSpanningCells(PRInt32 aRowIndex); // Returns PR_TRUE if there are any cells to the left of the column at // aColIndex and spanning into the column at aColIndex PRBool ColIsSpannedInto(PRInt32 aColIndex); // Returns PR_TRUE if there is a cell originating in aColIndex // which spans into the next col PRBool ColHasSpanningCells(PRInt32 aColIndex); // Allows rows to notify the table of additions or changes to a cell's width // The table uses this to update the appropriate column widths and to decide // whether to reinitialize (and then rebalance) or rebalance the table. If the // most extreme measure results (e.g. reinitialize) then PR_TRUE is returned // indicating that further calls are not going to accomplish anyting. PRBool CellChangedWidth(const nsTableCellFrame& aCellFrame, nscoord aPrevMinWidth, nscoord aPrevMaxWidth, PRBool aCellWasDestroyed = PR_FALSE); protected: PRBool HaveReflowedColGroups() const; void SetHaveReflowedColGroups(PRBool aValue); PRBool DidResizeReflow() const; void SetResizeReflow(PRBool aValue); public: PRBool NeedStrategyInit() const; void SetNeedStrategyInit(PRBool aValue); PRBool NeedStrategyBalance() const; void SetNeedStrategyBalance(PRBool aValue); PRBool IsBorderCollapse() const; PRBool NeedToCalcBCBorders() const; void SetNeedToCalcBCBorders(PRBool aValue); PRBool NeedToCollapseRows() const; void SetNeedToCollapseRows(PRBool aValue); PRBool NeedToCollapseColumns() const; void SetNeedToCollapseColumns(PRBool aValue); /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ virtual 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(PRInt32 aRowIndex, PRInt32 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 aFirstRowGroupFrame - first row group to be excluded * @param aLastRowGroupFrame - last sibling of aFirstRowGroupFrame that * should be excluded when reseting the row * indices. */ void ResetRowIndices(nsIFrame* aFirstRowGroupFrame = nsnull, nsIFrame* aLastRowGroupFrame = nsnull); nsVoidArray& GetColCache(); /** Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame */ static nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, nsIAtom* aFrameTypeIn = nsnull); protected: void SetBorderCollapse(PRBool aValue); void CalcBCBorders(); void ExpandBCDamageArea(nsRect& aRect) const; PRBool HadInitialReflow() const; void SetHadInitialReflow(PRBool aValue); void SetColumnDimensions(nscoord aHeight, const nsMargin& aReflowState); PRInt32 CollectRows(nsIFrame* aFrame, nsVoidArray& aCollection); public: /* ----- Cell Map public methods ----- */ PRInt32 GetStartRowIndex(nsTableRowGroupFrame& aRowGroupFrame); /** 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() const; /** returns the number of columns in this table after redundant columns have been removed */ virtual PRInt32 GetEffectiveColCount() const; virtual PRInt32 GetColCount() const; // return the last col index which isn't of type eColAnonymousCell PRInt32 GetIndexOfLastRealCol(); /** 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); /** return the minimum width of the table caption. Return 0 if there is no caption. */ nscoord GetMinCaptionWidth(); /** returns PR_TRUE if table-layout:auto */ virtual PRBool IsAutoLayout(); nscoord GetMinWidth() const; void SetMinWidth(nscoord aWidth); nscoord GetDesiredWidth() const; void SetDesiredWidth(nscoord aWidth); nscoord GetPreferredWidth() const; void SetPreferredWidth(nscoord aWidth); /*---------------- nsITableLayout methods ------------------------*/ /** Get the cell and associated data for a table cell from the frame's cellmap */ NS_IMETHOD GetCellDataAt(PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement* &aCell, //out params PRInt32& aStartRowIndex, PRInt32& aStartColIndex, PRInt32& aRowSpan, PRInt32& aColSpan, PRInt32& aActualRowSpan, PRInt32& aActualColSpan, PRBool& aIsSelected); /** Get the number of rows and column for a table from the frame's cellmap * Some rows may not have enough cells (the number returned is the maximum possible), * which displays as a ragged-right edge table */ NS_IMETHOD GetTableSize(PRInt32& aRowCount, PRInt32& aColCount); /*------------end of nsITableLayout methods -----------------------*/ public: #ifdef DEBUG void Dump(PRBool aDumpRows, PRBool aDumpCols, PRBool aDumpCellMap); static void DumpTableFrames(nsIFrame* aFrame); #endif protected: #ifdef DEBUG void DumpRowGroup(nsIFrame* aChildFrame); #endif // DATA MEMBERS nsAutoVoidArray mColFrames; struct TableBits { PRUint32 mHadInitialReflow:1; // has intial reflow happened PRUint32 mHaveReflowedColGroups:1; // have the col groups gotten their initial reflow PRUint32 mNeedStrategyBalance:1; // does the strategy needs to balance the table PRUint32 mNeedStrategyInit:1; // does the strategy needs to be initialized and then balance the table PRUint32 mHasPctCol:1; // does any cell or col have a pct width PRUint32 mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width) PRUint32 mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2) PRUint32 mIsBorderCollapse:1; // border collapsing model vs. separate model PRUint32 mRowInserted:1; PRUint32 mNeedSpecialReflow:1; PRUint32 mNeedToInitiateSpecialReflow:1; PRUint32 mInitiatedSpecialReflow:1; PRUint32 mNeedToCalcBCBorders:1; PRUint32 mLeftContBCBorder:8; PRUint32 mNeedToCollapseRows:1; // rows that have visibility need to be collapse PRUint32 mNeedToCollapseColumns:1; // colums that have visibility need to be collapsed PRUint32 :9; // unused } mBits; 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 nscoord mMinWidth; // XXX could store as PRUint16 with pixels nscoord mDesiredWidth; // XXX could store as PRUint16 with pixels nscoord mPreferredWidth; // XXX could store as PRUint16 with pixels // DEBUG REFLOW #if defined DEBUG_TABLE_REFLOW_TIMING public: static void DebugReflow(nsIFrame* aFrame, nsHTMLReflowState& aReflowState, nsHTMLReflowMetrics* aMetrics = nsnull, nsReflowStatus aStatus = NS_FRAME_COMPLETE); static void DebugReflowDone(nsIFrame* aFrame); enum nsMethod {eInit=0, eBalanceCols, eNonPctCols, eNonPctColspans, ePctCols}; static void DebugTimeMethod(nsMethod aMethod, nsTableFrame& aFrame, nsHTMLReflowState& aReflowState, PRBool aStart); nsReflowTimer* mTimer; #endif }; inline PRBool nsTableFrame::IsRowGroup(PRInt32 aDisplayType) const { return PRBool((NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == aDisplayType) || (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == aDisplayType) || (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == aDisplayType)); } inline void nsTableFrame::SetHadInitialReflow(PRBool aValue) { mBits.mHadInitialReflow = aValue; } inline PRBool nsTableFrame::HadInitialReflow() const { return (PRBool)mBits.mHadInitialReflow; } inline void nsTableFrame::SetHaveReflowedColGroups(PRBool aValue) { mBits.mHaveReflowedColGroups = aValue; } inline PRBool nsTableFrame::HaveReflowedColGroups() const { return (PRBool)mBits.mHaveReflowedColGroups; } inline PRBool nsTableFrame::HasPctCol() const { return (PRBool)mBits.mHasPctCol; } inline void nsTableFrame::SetHasPctCol(PRBool aValue) { mBits.mHasPctCol = (unsigned)aValue; } inline PRBool nsTableFrame::HasCellSpanningPctCol() const { return (PRBool)mBits.mCellSpansPctCol; } inline void nsTableFrame::SetHasCellSpanningPctCol(PRBool aValue) { mBits.mCellSpansPctCol = (unsigned)aValue; } inline PRBool nsTableFrame::NeedSpecialReflow() const { return (PRBool)mBits.mNeedSpecialReflow; } inline void nsTableFrame::SetNeedSpecialReflow(PRBool aValue) { mBits.mNeedSpecialReflow = (unsigned)aValue; } inline PRBool nsTableFrame::NeedToInitiateSpecialReflow() const { return (PRBool)mBits.mNeedToInitiateSpecialReflow; } inline void nsTableFrame::SetNeedToInitiateSpecialReflow(PRBool aValue) { mBits.mNeedToInitiateSpecialReflow = (unsigned)aValue; } inline PRBool nsTableFrame::InitiatedSpecialReflow() const { return (PRBool)mBits.mInitiatedSpecialReflow; } inline void nsTableFrame::SetInitiatedSpecialReflow(PRBool aValue) { mBits.mInitiatedSpecialReflow = (unsigned)aValue; } inline PRBool nsTableFrame::IsRowInserted() const { return (PRBool)mBits.mRowInserted; } inline void nsTableFrame::SetRowInserted(PRBool aValue) { mBits.mRowInserted = (unsigned)aValue; } inline void nsTableFrame::SetNeedToCollapseRows(PRBool aValue) { mBits.mNeedToCollapseRows = (unsigned)aValue; } inline PRBool nsTableFrame::NeedToCollapseRows() const { return (PRBool)mBits.mNeedToCollapseRows; } inline void nsTableFrame::SetNeedToCollapseColumns(PRBool aValue) { mBits.mNeedToCollapseColumns = (unsigned)aValue; } inline PRBool nsTableFrame::NeedToCollapseColumns() const { return (PRBool)mBits.mNeedToCollapseColumns; } inline nsFrameList& nsTableFrame::GetColGroups() { return NS_STATIC_CAST(nsTableFrame*, GetFirstInFlow())->mColGroups; } inline nsVoidArray& nsTableFrame::GetColCache() { return mColFrames; } inline void nsTableFrame::SetMinWidth(nscoord aWidth) { mMinWidth = aWidth; } inline void nsTableFrame::SetDesiredWidth(nscoord aWidth) { mDesiredWidth = aWidth; } inline void nsTableFrame::SetPreferredWidth(nscoord aWidth) { mPreferredWidth = aWidth; } inline PRBool nsTableFrame::IsBorderCollapse() const { return (PRBool)mBits.mIsBorderCollapse; } inline void nsTableFrame::SetBorderCollapse(PRBool aValue) { mBits.mIsBorderCollapse = aValue; } inline PRBool nsTableFrame::NeedToCalcBCBorders() const { return (PRBool)mBits.mNeedToCalcBCBorders; } inline void nsTableFrame::SetNeedToCalcBCBorders(PRBool aValue) { mBits.mNeedToCalcBCBorders = (unsigned)aValue; } inline nscoord nsTableFrame::GetContinuousLeftBCBorderWidth(float aPixelsToTwips) const { return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mBits.mLeftContBCBorder); } enum nsTableIteration { eTableLTR = 0, eTableRTL = 1, eTableDIR = 2 }; class nsTableIterator { public: nsTableIterator(nsIFrame& aSource, nsTableIteration aType); nsTableIterator(nsFrameList& aSource, nsTableIteration aType); nsIFrame* First(); nsIFrame* Next(); PRBool IsLeftToRight(); PRInt32 Count(); protected: void Init(nsIFrame* aFirstChild, nsTableIteration aType); PRBool mLeftToRight; nsIFrame* mFirstListChild; nsIFrame* mFirstChild; nsIFrame* mCurrentChild; PRInt32 mCount; }; #define ABORT0() \ {NS_ASSERTION(PR_FALSE, "CellIterator program error"); \ return;} #define ABORT1(aReturn) \ {NS_ASSERTION(PR_FALSE, "CellIterator program error"); \ return aReturn;} #define GET_PIXELS_TO_TWIPS(presContext,var) \ float var = (presContext)->ScaledPixelsToTwips(); #define GET_TWIPS_TO_PIXELS(presContext,var) \ float var = (presContext)->ScaledPixelsToTwips(); \ var = 1.0f / var; #endif