/* -*- 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.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/NPL/ * * 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 Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "nsTableColGroupFrame.h" #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsIHTMLTableColElement.h" #include "nsIDOMHTMLTableColElement.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" #include "nsIHTMLContent.h" #include "nsHTMLParts.h" #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsCOMPtr.h" #include "nsCSSRendering.h" #include "nsIPresShell.h" #include "nsLayoutAtoms.h" static NS_DEFINE_IID(kIHTMLTableColElementIID, NS_IHTMLTABLECOLELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLTableColElementIID, NS_IDOMHTMLTABLECOLELEMENT_IID); #define COLGROUP_TYPE_CONTENT 0x0 #define COLGROUP_TYPE_ANONYMOUS_COL 0x1 #define COLGROUP_TYPE_ANONYMOUS_CELL 0x2 nsTableColGroupType nsTableColGroupFrame::GetType() const { switch(mBits.mType) { case COLGROUP_TYPE_ANONYMOUS_COL: return eColGroupAnonymousCol; case COLGROUP_TYPE_ANONYMOUS_CELL: return eColGroupAnonymousCell; default: return eColGroupContent; } } void nsTableColGroupFrame::SetType(nsTableColGroupType aType) { mBits.mType = aType - eColGroupContent; } void nsTableColGroupFrame::ResetColIndices(nsIPresContext* aPresContext, nsIFrame* aFirstColGroup, PRInt32 aFirstColIndex, nsIFrame* aStartColFrame) { nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)aFirstColGroup; PRInt32 colIndex = aFirstColIndex; while (colGroupFrame) { nsCOMPtr cgType; colGroupFrame->GetFrameType(getter_AddRefs(cgType)); if (nsLayoutAtoms::tableColGroupFrame == cgType.get()) { // reset the starting col index for the first cg only if // aFirstColIndex is smaller than the existing starting col index if ((colIndex != aFirstColIndex) || (colIndex < colGroupFrame->GetStartColumnIndex())) { colGroupFrame->SetStartColumnIndex(colIndex); } nsIFrame* colFrame = aStartColFrame; if (!colFrame || (colIndex != aFirstColIndex)) { colGroupFrame->FirstChild(aPresContext, nsnull, &colFrame); } while (colFrame) { nsCOMPtr colType; colFrame->GetFrameType(getter_AddRefs(colType)); if (nsLayoutAtoms::tableColFrame == colType.get()) { ((nsTableColFrame*)colFrame)->SetColIndex(colIndex); colIndex++; } colFrame->GetNextSibling(&colFrame); } } colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame); } } NS_IMETHODIMP nsTableColGroupFrame::AddColsToTable(nsIPresContext& aPresContext, PRInt32 aFirstColIndex, PRBool aResetSubsequentColIndices, nsIFrame* aFirstFrame, nsIFrame* aLastFrame) { nsresult rv = NS_OK; nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!(NS_SUCCEEDED(rv) && tableFrame && aFirstFrame)) { return rv; } // set the col indices of the col frames and and add col info to the table PRInt32 colIndex = aFirstColIndex; nsIFrame* kidFrame = aFirstFrame; PRBool foundLastFrame = PR_FALSE; while (kidFrame) { nsIAtom* kidType; kidFrame->GetFrameType(&kidType); if (nsLayoutAtoms::tableColFrame == kidType) { ((nsTableColFrame*)kidFrame)->SetColIndex(colIndex); if (!foundLastFrame) { tableFrame->InsertCol(aPresContext, (nsTableColFrame &)*kidFrame, colIndex); mColCount++; } colIndex++; } NS_IF_RELEASE(kidType); if (kidFrame == aLastFrame) { foundLastFrame = PR_TRUE; } kidFrame->GetNextSibling(&kidFrame); } if (aResetSubsequentColIndices) { nsIFrame* nextSibling; GetNextSibling(&nextSibling); if (nextSibling) { ResetColIndices(&aPresContext, nextSibling, colIndex); } } return rv; } // this is called when a col frame doesn't have an explicit col group parent. nsTableColGroupFrame* nsTableColGroupFrame::FindParentForAppendedCol(nsTableFrame* aTableFrame, nsTableColType aColType) { nsVoidArray& cols = aTableFrame->GetColCache(); PRInt32 numCols = cols.Count(); nsIFrame* lastColGroup; nsIFrame* lastCol = (nsIFrame*)cols.ElementAt(numCols - 1); if (!lastCol) return nsnull; // no columns so no colgroups lastCol->GetParent(&lastColGroup); if (!lastColGroup) return nsnull; // shouldn't happen nsTableColGroupFrame* relevantColGroup = (nsTableColGroupFrame *)lastColGroup; nsTableColGroupType relevantColGroupType = relevantColGroup->GetType(); if (eColGroupAnonymousCell == relevantColGroupType) { if (eColAnonymousCell == aColType) { return relevantColGroup; } else { // find the next to last col group for (PRInt32 colX = numCols - 2; colX >= 0; colX--) { nsTableColFrame* colFrame = (nsTableColFrame*)cols.ElementAt(colX); nsTableColGroupFrame* colGroupFrame; colFrame->GetParent((nsIFrame**)&colGroupFrame); nsTableColGroupType cgType = colGroupFrame->GetType(); if (cgType != relevantColGroupType) { relevantColGroup = colGroupFrame; relevantColGroupType = cgType; break; } else if (0 == colX) { return nsnull; } } } } if (eColGroupAnonymousCol == relevantColGroupType) { if ((eColContent == aColType) || (eColAnonymousCol == aColType)) { return relevantColGroup; } } return nsnull; } PRBool nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame* aTableFrame, nsIFrame** aLastColGroup) { *aLastColGroup = nsnull; nsFrameList colGroups = aTableFrame->GetColGroups(); nsIFrame* nextToLastColGroup = nsnull; nsIFrame* lastColGroup = colGroups.FirstChild(); while(lastColGroup) { nsIFrame* next; lastColGroup->GetNextSibling(&next); if (next) { nextToLastColGroup = lastColGroup; lastColGroup = next; } else { break; } } if (!lastColGroup) return PR_TRUE; // there are no col group frames nsTableColGroupType lastColGroupType = ((nsTableColGroupFrame *)lastColGroup)->GetType(); if (eColGroupAnonymousCell == lastColGroupType) { *aLastColGroup = nextToLastColGroup; return PR_FALSE; } else { *aLastColGroup = lastColGroup; return PR_TRUE; } } // don't set mColCount here, it is done in AddColsToTable NS_IMETHODIMP nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aChildList) { nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); if (!aChildList) { nsIFrame* firstChild; tableFrame->CreateAnonymousColFrames(*aPresContext, *this, GetSpan(), eColAnonymousColGroup, PR_FALSE, nsnull, &firstChild); if (firstChild) { SetInitialChildList(aPresContext, aListName, firstChild); } return NS_OK; } nsIFrame* kidFrame = aChildList; while (kidFrame) { nsIAtom* kidType; kidFrame->GetFrameType(&kidType); if (nsLayoutAtoms::tableColFrame == kidType) { // Set the preliminary values for the column frame PRInt32 span = ((nsTableColFrame*)kidFrame)->GetSpan(); if (span > 1) { nsTableColFrame* firstSpannedCol; tableFrame->CreateAnonymousColFrames(*aPresContext, *this, span - 1, eColAnonymousCol, PR_FALSE, (nsTableColFrame*)kidFrame, (nsIFrame **)&firstSpannedCol); nsIFrame* spanner = kidFrame; kidFrame->GetNextSibling(&kidFrame); // need to do this before we insert the new frames nsFrameList newChildren(aChildList); // used as a convience to hook up siblings newChildren.InsertFrames(this, (nsTableColFrame*)spanner, (nsIFrame *)firstSpannedCol); NS_RELEASE(kidType); continue; } } NS_IF_RELEASE(kidType); kidFrame->GetNextSibling(&kidFrame); } mFrames.AppendFrames(this, aChildList); return NS_OK; } // Helper function. It marks the table frame as dirty and generates // a reflow command nsresult nsTableColGroupFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIFrame* aTableFrame) { nsFrameState frameState; nsIFrame* tableParentFrame; nsIReflowCommand* reflowCmd; nsresult rv; // Mark the table frame as dirty aTableFrame->GetFrameState(&frameState); frameState |= NS_FRAME_IS_DIRTY; aTableFrame->SetFrameState(frameState); // Target the reflow comamnd at its parent frame aTableFrame->GetParent(&tableParentFrame); rv = NS_NewHTMLReflowCommand(&reflowCmd, tableParentFrame, nsIReflowCommand::ReflowDirty); if (NS_SUCCEEDED(rv)) { // Add the reflow command rv = aPresShell.AppendReflowCommand(reflowCmd); NS_RELEASE(reflowCmd); } return rv; } NS_IMETHODIMP nsTableColGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aFrameList) { mFrames.AppendFrames(this, aFrameList); InsertColsReflow(*aPresContext, aPresShell, mColCount, aFrameList); return NS_OK; } NS_IMETHODIMP nsTableColGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aPrevFrameIn, nsIFrame* aFrameList) { nsFrameList frames(aFrameList); // convience for getting last frame nsIFrame* lastFrame = frames.LastChild(); mFrames.InsertFrames(this, aPrevFrameIn, aFrameList); nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(aPresContext, this, aPrevFrameIn, nsLayoutAtoms::tableColFrame); PRInt32 colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : 0; InsertColsReflow(*aPresContext, aPresShell, colIndex, aFrameList, lastFrame); return NS_OK; } void nsTableColGroupFrame::InsertColsReflow(nsIPresContext& aPresContext, nsIPresShell& aPresShell, PRInt32 aColIndex, nsIFrame* aFirstFrame, nsIFrame* aLastFrame) { AddColsToTable(aPresContext, aColIndex, PR_TRUE, aFirstFrame, aLastFrame); nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); tableFrame->InvalidateColumnWidths(); // Generate a reflow command so we reflow the table AddTableDirtyReflowCommand(&aPresContext, aPresShell, tableFrame); } void nsTableColGroupFrame::RemoveChild(nsIPresContext& aPresContext, nsTableColFrame& aChild, PRBool aResetColIndices) { PRInt32 colIndex = 0; nsIFrame* nextChild = nsnull; if (aResetColIndices) { colIndex = aChild.GetColIndex(); aChild.GetNextSibling(&nextChild); } if (mFrames.DestroyFrame(&aPresContext, (nsIFrame*)&aChild)) { mColCount--; if (aResetColIndices) { ResetColIndices(&aPresContext, this, colIndex, nextChild); } } } // this removes children form the last col group (eColGroupAnonymousCell) in the // table only,so there is no need to reset col indices for subsequent col groups. void nsTableColGroupFrame::RemoveChildrenAtEnd(nsIPresContext& aPresContext, PRInt32 aNumChildrenToRemove) { PRInt32 numToRemove = aNumChildrenToRemove; if (numToRemove > mColCount) { NS_ASSERTION(PR_FALSE, "invalid arg to RemoveChildrenAtEnd"); numToRemove = mColCount; } PRInt32 offsetOfFirstRemoval = mColCount - numToRemove; PRInt32 offsetX = 0; nsIFrame* kidFrame = mFrames.FirstChild(); while(kidFrame) { nsIAtom* kidType; kidFrame->GetFrameType(&kidType); if (nsLayoutAtoms::tableColFrame == kidType) { offsetX++; if (offsetX > offsetOfFirstRemoval) { nsIFrame* byebye = kidFrame; kidFrame->GetNextSibling(&kidFrame); mFrames.DestroyFrame(&aPresContext, byebye); NS_RELEASE(kidType); continue; } } NS_IF_RELEASE(kidType); kidFrame->GetNextSibling(&kidFrame); } } NS_IMETHODIMP nsTableColGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame) { if (!aOldFrame) return NS_OK; nsIAtom* frameType = nsnull; aOldFrame->GetFrameType(&frameType); if (nsLayoutAtoms::tableColFrame == frameType) { nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame; PRInt32 colIndex = colFrame->GetColIndex(); RemoveChild(*aPresContext, *colFrame, PR_TRUE); nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); if (tableFrame) { tableFrame->RemoveCol(*aPresContext, this, colIndex, PR_TRUE, PR_TRUE); } tableFrame->InvalidateColumnWidths(); // Generate a reflow command so we reflow the table AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } else { mFrames.DestroyFrame(aPresContext, aOldFrame); } NS_IF_RELEASE(frameType); return NS_OK; } NS_METHOD nsTableColGroupFrame::Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer) { if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { nsCompatibility mode; aPresContext->GetCompatibilityMode(&mode); if (eCompatibility_Standard == mode) { const nsStyleDisplay* disp = (const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display); if (disp->IsVisibleOrCollapsed()) { const nsStyleSpacing* spacing = (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing); const nsStyleColor* color = (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); nsRect rect(0, 0, mRect.width, mRect.height); nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *color, *spacing, 0, 0); } } } PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); return NS_OK; } PRIntn nsTableColGroupFrame::GetSkipSides() const { PRIntn skip = 0; if (nsnull != mPrevInFlow) { skip |= 1 << NS_SIDE_TOP; } if (nsnull != mNextInFlow) { skip |= 1 << NS_SIDE_BOTTOM; } return skip; } NS_IMETHODIMP nsTableColGroupFrame::GetFrameForPoint(nsIPresContext* aPresContext, const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, nsIFrame** aFrame) { // this should act like a block, so we need to override return GetFrameForPointUsing(aPresContext, aPoint, nsnull, aWhichLayer, (aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND), aFrame); } NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame", aReflowState.reason); NS_ASSERTION(nsnull!=mContent, "bad state -- null content for frame"); nsresult rv=NS_OK; // for every content child that (is a column thingy and does not already have a frame) // create a frame and adjust it's style nsIFrame* kidFrame = nsnull; if (eReflowReason_Incremental == aReflowState.reason) { rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus); } for (kidFrame = mFrames.FirstChild(); nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { // Give the child frame a chance to reflow, even though we know it'll have 0 size nsHTMLReflowMetrics kidSize(nsnull); // XXX Use a valid reason... nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, nsSize(0,0), eReflowReason_Initial); nsReflowStatus status; ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, status); FinishReflowChild(kidFrame, aPresContext, kidSize, 0, 0, 0); } aDesiredSize.width=0; aDesiredSize.height=0; aDesiredSize.ascent=aDesiredSize.height; aDesiredSize.descent=0; if (nsnull!=aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width=0; aDesiredSize.maxElementSize->height=0; } aStatus = NS_FRAME_COMPLETE; return rv; } NS_METHOD nsTableColGroupFrame::IncrementalReflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = NS_OK; // determine if this frame is the target or not nsIFrame *target=nsnull; rv = aReflowState.reflowCommand->GetTarget(target); if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target)) { if (this==target) rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus); else { // Get the next frame in the reflow chain nsIFrame* nextFrame; aReflowState.reflowCommand->GetNext(nextFrame); rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame); } } return rv; } NS_METHOD nsTableColGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = NS_OK; aStatus = NS_FRAME_COMPLETE; nsIReflowCommand::ReflowType type; aReflowState.reflowCommand->GetType(type); nsIFrame *objectFrame; aReflowState.reflowCommand->GetChildFrame(objectFrame); const nsStyleDisplay *childDisplay=nsnull; if (nsnull!=objectFrame) objectFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); switch (type) { case nsIReflowCommand::StyleChanged : rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); break; case nsIReflowCommand::ContentChanged : NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); rv = NS_ERROR_ILLEGAL_VALUE; break; default: NS_NOTYETIMPLEMENTED("unexpected reflow command type"); rv = NS_ERROR_NOT_IMPLEMENTED; break; } return rv; } NS_METHOD nsTableColGroupFrame::IR_StyleChanged(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = NS_OK; // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here // XXX: we can optimize this when we know which style attribute changed nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); if ((NS_SUCCEEDED(rv)) && tableFrame) { tableFrame->InvalidateColumnWidths(); tableFrame->InvalidateFirstPassCache(); } return rv; } NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, nsIFrame * aNextFrame) { nsresult rv; // Pass along the reflow command nsHTMLReflowMetrics desiredSize(nsnull); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aNextFrame, nsSize(aReflowState.availableWidth, aReflowState.availableHeight)); rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, aStatus); aNextFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); if (NS_FAILED(rv)) return rv; nsTableFrame *tableFrame=nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { // compare the new col count to the old col count. // If they are the same, we just need to rebalance column widths // If they differ, we need to fix up other column groups and the column cache tableFrame->InvalidateColumnWidths(); } return rv; } nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() { return GetNextColumn(nsnull); } nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame) { nsTableColFrame *result = nsnull; nsIFrame *childFrame = aChildFrame; if (nsnull==childFrame) childFrame = mFrames.FirstChild(); while (nsnull!=childFrame) { const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) { result = (nsTableColFrame *)childFrame; break; } childFrame->GetNextSibling(&childFrame); } return result; } nsTableColFrame * nsTableColGroupFrame::GetColumnAt (PRInt32 aColIndex) { nsTableColFrame *result = nsnull; PRInt32 count = 0; nsIFrame *childFrame = mFrames.FirstChild(); while (nsnull!=childFrame) { const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) { nsTableColFrame *col = (nsTableColFrame *)childFrame; count++; if (aColIndex<=count) { result = col; } } childFrame->GetNextSibling(&childFrame); } return result; } PRInt32 nsTableColGroupFrame::GetSpan() { PRInt32 span = 1; nsCOMPtr iContent; nsresult rv = GetContent(getter_AddRefs(iContent)); if (NS_FAILED(rv) || !iContent) return rv; // col group element derives from col element nsIDOMHTMLTableColElement* cgContent = nsnull; rv = iContent->QueryInterface(kIDOMHTMLTableColElementIID, (void **)&cgContent); if (cgContent && NS_SUCCEEDED(rv)) { cgContent->GetSpan(&span); // XXX why does this work!! if (span == -1) { span = 1; } NS_RELEASE(cgContent); } return span; } /** returns colcount because it is frequently used in the context of * shuffling relative colgroup order, and it's convenient to not have to * call GetColumnCount redundantly. */ PRInt32 nsTableColGroupFrame::SetStartColumnIndex (int aIndex) { PRInt32 result = mColCount; if (aIndex != mStartColIndex) { mStartColIndex = aIndex; result = GetColCount(); } return result; } // this could be optimized by using col group frame starting indicies, // but typically there aren't enough very large col groups for the added complexity. nsTableColGroupFrame* nsTableColGroupFrame::GetColGroupFrameContaining(nsIPresContext* aPresContext, nsFrameList& aColGroupList, nsTableColFrame& aColFrame) { nsIFrame* childFrame = aColGroupList.FirstChild(); while (childFrame) { nsIAtom* frameType = nsnull; childFrame->GetFrameType(&frameType); if (nsLayoutAtoms::tableColGroupFrame == frameType) { nsTableColFrame* colFrame = nsnull; childFrame->FirstChild(aPresContext, nsnull, (nsIFrame **)&colFrame); while (colFrame) { if (colFrame == &aColFrame) { NS_RELEASE(frameType); return (nsTableColGroupFrame *)childFrame; } colFrame->GetNextSibling((nsIFrame **)&colFrame); } } NS_IF_RELEASE(frameType); childFrame->GetNextSibling(&childFrame); } return nsnull; } void nsTableColGroupFrame::DeleteColFrame(nsIPresContext* aPresContext, nsTableColFrame* aColFrame) { mFrames.DestroyFrame(aPresContext, aColFrame); } /* ----- global methods ----- */ nsresult NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) { NS_PRECONDITION(aNewFrame, "null OUT ptr"); if (nsnull == aNewFrame) { return NS_ERROR_NULL_POINTER; } nsTableColGroupFrame* it = new (aPresShell) nsTableColGroupFrame; if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } *aNewFrame = it; return NS_OK; } NS_IMETHODIMP nsTableColGroupFrame::GetFrameType(nsIAtom** aType) const { NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); *aType = nsLayoutAtoms::tableColGroupFrame; NS_ADDREF(*aType); return NS_OK; } #ifdef DEBUG NS_IMETHODIMP nsTableColGroupFrame::GetFrameName(nsString& aResult) const { return MakeFrameName("TableColGroup", aResult); } NS_IMETHODIMP nsTableColGroupFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const { if (!aResult) { return NS_ERROR_NULL_POINTER; } PRUint32 sum = sizeof(*this); *aResult = sum; return NS_OK; } #endif