pjs/layout/tables/nsTableRowFrame.cpp

373 строки
13 KiB
C++
Исходник Обычный вид История

1998-04-14 00:24:54 +04:00
/* -*- 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.
*/
#include "nsTableRowFrame.h"
#include "nsIRenderingContext.h"
#include "nsIPresContext.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIContent.h"
#include "nsIContentDelegate.h"
#include "nsTableFrame.h"
#include "nsTableCellFrame.h"
#include "nsTableCell.h"
#include "nsCellLayoutData.h"
#include "nsIView.h"
1998-04-14 00:24:54 +04:00
#ifdef NS_DEBUG
static PRBool gsDebug1 = PR_FALSE;
static PRBool gsDebug2 = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
#else
static const PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug2 = PR_FALSE;
#endif
static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
nsTableRowFrame::nsTableRowFrame(nsIContent* aContent,
PRInt32 aIndexInParent,
nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aIndexInParent, aParentFrame),
mTallestCell(0)
{
}
nsTableRowFrame::~nsTableRowFrame()
{
}
void nsTableRowFrame::ResetMaxChildHeight()
{
mTallestCell=0;
}
void nsTableRowFrame::SetMaxChildHeight(PRInt32 aChildHeight)
{
if (mTallestCell<aChildHeight)
mTallestCell = aChildHeight;
}
NS_METHOD nsTableRowFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
1998-04-14 00:24:54 +04:00
{
// for debug...
if (nsIFrame::GetShowFrameBorders()) {
aRenderingContext.SetColor(NS_RGB(0,0,128));
aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
}
PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
return NS_OK;
1998-04-14 00:24:54 +04:00
}
// aDirtyRect is in our coordinate system
// child rect's are also in our coordinate system
/** overloaded method from nsContainerFrame. The difference is that
* we don't want to clip our children, so a cell can do a rowspan
*/
void nsTableRowFrame::PaintChildren(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
nsIFrame* kid = mFirstChild;
while (nsnull != kid) {
nsIView *pView;
kid->GetView(pView);
if (nsnull == pView) {
nsRect kidRect;
kid->GetRect(kidRect);
nsRect damageArea(aDirtyRect);
// Translate damage area into kid's coordinate system
nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y,
damageArea.width, damageArea.height);
aRenderingContext.PushState();
aRenderingContext.Translate(kidRect.x, kidRect.y);
kid->Paint(aPresContext, aRenderingContext, kidDamageArea);
if (nsIFrame::GetShowFrameBorders()) {
aRenderingContext.SetColor(NS_RGB(255,0,0));
aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height);
}
aRenderingContext.PopState();
} else {
NS_RELEASE(pView);
}
kid->GetNextSibling(kid);
1998-04-14 00:24:54 +04:00
}
}
/** returns the tallest child in this row (ignoring any cell with rowspans) */
PRInt32 nsTableRowFrame::GetTallestChild() const
{
return mTallestCell;
}
/*
want to use min space the child can fit in to
determine its real size, unless fixed columns sizes
are present.
*/
/** Layout the entire row.
* This method stacks rows horizontally according to HTML 4.0 rules.
* Rows are responsible for layout of their children.
*/
NS_METHOD
1998-04-14 00:24:54 +04:00
nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
const nsSize& aMaxSize,
nsSize* aMaxElementSize,
ReflowStatus& aStatus)
1998-04-14 00:24:54 +04:00
{
if (gsDebug1==PR_TRUE)
printf("nsTableRowFrame::ResizeReflow - %p with aMaxSize = %d, %d\n",
this, aMaxSize.width, aMaxSize.height);
#ifdef NS_DEBUG
PreReflowCheck();
#endif
1998-04-21 02:49:15 +04:00
//nsresult result = NS_OK;
1998-04-14 00:24:54 +04:00
PRInt32 maxCellHeight = 0;
ResetMaxChildHeight();
aStatus = frComplete;
1998-04-14 00:24:54 +04:00
mFirstContentOffset = mLastContentOffset = 0;
nsSize availSize(aMaxSize);
nsSize maxSize(0, 0);
nsSize kidMaxSize(0,0);
nsSize kidMaxElementSize(0,0);
1998-04-14 00:24:54 +04:00
nsReflowMetrics kidSize;
nscoord cellXOffset = 0;
nscoord maxAscent = 0;
nscoord maxDescent = 0;
PRInt32 kidIndex = 0;
1998-04-21 02:49:15 +04:00
PRInt32 lastIndex = mContent->ChildCount();
1998-04-14 00:24:54 +04:00
nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
// Row doesn't factor in insets, the cells do that
nsTableFrame *tableFrame;
mContentParent->GetContentParent((nsIFrame*&)tableFrame);
1998-04-14 00:24:54 +04:00
for (;;) {
1998-04-21 02:49:15 +04:00
nsTableCell* cell = (nsTableCell *)(mContent->ChildAt(kidIndex)); // cell: REFCNT++
if (nsnull == cell) {
aStatus = frComplete;
1998-04-14 00:24:54 +04:00
break;
}
1998-04-21 02:49:15 +04:00
// get next frame, creating one if needed
nsIFrame* kidFrame=nsnull;
if (nsnull!=prevKidFrame)
prevKidFrame->GetNextSibling(kidFrame); // no need to check for an error, just see if it returned null...
else
ChildAt(0, kidFrame);
1998-04-14 00:24:54 +04:00
if (nsnull==kidFrame)
{
nsIContentDelegate* kidDel;
1998-04-21 02:49:15 +04:00
kidDel = cell->GetDelegate(aPresContext);
kidFrame = kidDel->CreateFrame(aPresContext, cell, kidIndex, this);
1998-04-14 00:24:54 +04:00
mChildCount++;
NS_RELEASE(kidDel);
// Resolve style
nsIStyleContext* kidStyleContext =
1998-04-21 02:49:15 +04:00
aPresContext->ResolveStyleContextFor(cell, this);
1998-04-14 00:24:54 +04:00
NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid.");
kidFrame->SetStyleContext(kidStyleContext);
NS_RELEASE(kidStyleContext);
}
// Try to reflow the child into the available space.
if (NS_UNCONSTRAINEDSIZE == availSize.width)
{ // Each cell is given the entire row width to try to lay out into
aStatus = ReflowChild(kidFrame, aPresContext, kidSize, availSize, &kidMaxSize);
1998-04-14 00:24:54 +04:00
if (gsDebug1) printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
aStatus==frComplete?"complete":"NOT complete",
1998-04-14 00:24:54 +04:00
kidSize.width, kidSize.height, kidMaxSize.width, kidMaxSize.height);
nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &kidSize, &kidMaxSize);
tableFrame->SetCellLayoutData(&kidLayoutData, cell);
}
else
{ // we're in a constrained situation, so get the avail width from the known column widths
nsTableFrame *innerTableFrame;
mContentParent->GetContentParent((nsIFrame*&)innerTableFrame);
1998-04-14 00:24:54 +04:00
nsCellLayoutData *cellData = innerTableFrame->GetCellLayoutData(cell);
PRInt32 cellStartingCol = cell->GetColIndex();
PRInt32 cellColSpan = cell->GetColSpan();
PRInt32 availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
availWidth += innerTableFrame->GetColumnWidth(cellStartingCol+numColSpan);
NS_ASSERTION(0<availWidth, "illegal width for this column");
nsSize availSizeWithSpans(availWidth, availSize.height);
aStatus = ReflowChild(kidFrame, aPresContext, kidSize, availSizeWithSpans, &kidMaxSize);
1998-04-14 00:24:54 +04:00
if (gsDebug1) printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
aStatus==frComplete?"complete":"NOT complete",
1998-04-14 00:24:54 +04:00
kidSize.width, kidSize.height, kidMaxSize.width, kidMaxSize.height);
// SEC: TODO: this next block could be smarter,
// with this frame caching the column x offsets along with the widths
cellXOffset = 0;
for (PRInt32 colIndex=0; colIndex<cell->GetColIndex(); colIndex++)
cellXOffset += innerTableFrame->GetColumnWidth(colIndex);
}
PRInt32 rowSpan = cell->GetRowSpan();
if ((1==rowSpan) && (maxCellHeight<kidSize.height))
maxCellHeight = kidSize.height;
// SEC: the next line is probably unnecessary
// Place the child since some of it's content fit in us.
1998-04-21 02:49:15 +04:00
if (PR_TRUE==gsDebug1)
printf ("row: placing cell at %d, %d, %d, %d\n",
cellXOffset, 0, kidSize.width, kidSize.height);
1998-04-14 00:24:54 +04:00
kidFrame->SetRect(nsRect(cellXOffset, 0, kidSize.width, kidSize.height));
if (kidSize.width > maxSize.width) {
maxSize.width = kidSize.width;
}
if (NS_UNCONSTRAINEDSIZE==aMaxSize.height)
{
if ((1==rowSpan) && (kidSize.height > maxSize.height))
maxSize.height = kidSize.height;
if (kidMaxSize.height > kidMaxElementSize.height)
kidMaxElementSize.height = kidMaxSize.height;
}
else
{ // in the constrained height case, our maxElementSize is the height of our tallest cell
if ((1==rowSpan) && (kidSize.height > maxSize.height))
maxSize.height = kidSize.height;
if (maxSize.height > kidMaxElementSize.height)
kidMaxElementSize.height = maxSize.height;
1998-04-14 00:24:54 +04:00
}
kidMaxElementSize.width += kidMaxSize.width;
1998-04-14 00:24:54 +04:00
if (NS_UNCONSTRAINEDSIZE!=cellXOffset)
cellXOffset+=kidSize.width;
if (cellXOffset<=0)
cellXOffset = NS_UNCONSTRAINEDSIZE; // handle overflow
// Link child frame into the list of children
if (nsnull != prevKidFrame) {
prevKidFrame->SetNextSibling(kidFrame);
} else {
// Our first child (**blush**)
1998-04-15 01:45:28 +04:00
if (gsDebug1) printf ("row frame %p, setting first child to %p\n", this, kidFrame);
1998-04-14 00:24:54 +04:00
mFirstChild = kidFrame;
SetFirstContentOffset(kidFrame);
if (gsDebug1) printf("ROW: set first content offset to %d\n", GetFirstContentOffset()); //@@@
}
prevKidFrame = kidFrame;
kidIndex++;
if (frNotComplete == aStatus) {
1998-04-14 00:24:54 +04:00
// If the child didn't finish layout then it means that it used
// up all of our available space (or needs us to split).
mLastContentIsComplete = PR_FALSE;
break;
}
1998-04-21 02:49:15 +04:00
NS_RELEASE(cell); // kid: REFCNT--
1998-04-14 00:24:54 +04:00
}
if (nsnull != prevKidFrame) {
if (!IsLastChild(prevKidFrame))
{
mGeometricParent->List();
}
NS_ASSERTION(IsLastChild(prevKidFrame), "unexpected last child");
1998-04-14 00:24:54 +04:00
SetLastContentOffset(prevKidFrame);
}
// Return our size and our result
aDesiredSize.width = cellXOffset;
aDesiredSize.height = maxSize.height;
aDesiredSize.ascent = maxAscent;
aDesiredSize.descent = maxDescent;
if (nsnull != aMaxElementSize) {
*aMaxElementSize = kidMaxElementSize;
1998-04-14 00:24:54 +04:00
}
SetMaxChildHeight(maxCellHeight); // remember height of tallest child who doesn't have a row span
#ifdef NS_DEBUG
PostReflowCheck(aStatus);
1998-04-14 00:24:54 +04:00
#endif
1998-04-15 01:45:28 +04:00
if (gsDebug1==PR_TRUE)
{
if (nsnull!=aMaxElementSize)
printf("nsTableRowFrame::RR returning: %s with aDesiredSize=%d,%d, aMES=%d,%d\n",
aStatus==frComplete?"Complete":"Not Complete",
1998-04-15 01:45:28 +04:00
aDesiredSize.width, aDesiredSize.height,
aMaxElementSize->width, aMaxElementSize->height);
else
printf("nsTableRowFrame::RR returning: %s with aDesiredSize=%d,%d, aMES=NSNULL\n",
aStatus==frComplete?"Complete":"Not Complete",
1998-04-15 01:45:28 +04:00
aDesiredSize.width, aDesiredSize.height);
}
// testing...
aStatus = frComplete;
return NS_OK;
1998-04-14 00:24:54 +04:00
}
NS_METHOD
1998-04-14 00:24:54 +04:00
nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
const nsSize& aMaxSize,
nsReflowCommand& aReflowCommand,
ReflowStatus& aStatus)
1998-04-14 00:24:54 +04:00
{
if (gsDebug1==PR_TRUE) printf("nsTableRowFrame::IncrementalReflow\n");
aStatus = frComplete;
return NS_OK;
1998-04-14 00:24:54 +04:00
}
NS_METHOD nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
nsIFrame* aParent,
nsIFrame*& aContinuingFrame)
1998-04-14 00:24:54 +04:00
{
1998-04-15 01:45:28 +04:00
if (gsDebug1==PR_TRUE) printf("nsTableRowFrame::CreateContinuingFrame\n");
1998-04-14 00:24:54 +04:00
nsTableRowFrame* cf = new nsTableRowFrame(mContent, mIndexInParent, aParent);
PrepareContinuingFrame(aPresContext, aParent, cf);
aContinuingFrame = cf;
return NS_OK;
1998-04-14 00:24:54 +04:00
}
nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult,
nsIContent* aContent,
PRInt32 aIndexInParent,
nsIFrame* aParent)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsIFrame* it = new nsTableRowFrame(aContent, aIndexInParent, aParent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aInstancePtrResult = it;
return NS_OK;
}