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 "nsTableCellFrame.h"
|
|
|
|
#include "nsBodyFrame.h"
|
|
|
|
#include "nsReflowCommand.h"
|
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsIRenderingContext.h"
|
|
|
|
#include "nsCSSRendering.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIContentDelegate.h"
|
|
|
|
#include "nsCSSLayout.h"
|
|
|
|
|
|
|
|
#ifdef NS_DEBUG
|
|
|
|
static PRBool gsDebug = PR_FALSE;
|
|
|
|
//#define NOISY
|
|
|
|
//#define NOISY_FLOW
|
|
|
|
#else
|
|
|
|
static const PRBool gsDebug = PR_FALSE;
|
|
|
|
#endif
|
|
|
|
|
1998-04-25 22:48:48 +04:00
|
|
|
static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID);
|
1998-04-22 10:37:57 +04:00
|
|
|
static NS_DEFINE_IID(kStyleBorderSID, NS_STYLEBORDER_SID);
|
1998-04-14 00:24:54 +04:00
|
|
|
static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID);
|
1998-04-25 22:48:48 +04:00
|
|
|
static NS_DEFINE_IID(kStyleTextSID, NS_STYLETEXT_SID);
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
nsTableCellFrame::nsTableCellFrame(nsIContent* aContent,
|
|
|
|
PRInt32 aIndexInParent,
|
|
|
|
nsIFrame* aParentFrame)
|
|
|
|
: nsContainerFrame(aContent, aIndexInParent, aParentFrame)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsTableCellFrame::~nsTableCellFrame()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext,
|
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect)
|
1998-04-14 00:24:54 +04:00
|
|
|
{
|
|
|
|
nsStyleColor* myColor =
|
|
|
|
(nsStyleColor*)mStyleContext->GetData(kStyleColorSID);
|
1998-04-22 10:37:57 +04:00
|
|
|
nsStyleBorder* myBorder =
|
|
|
|
(nsStyleBorder*)mStyleContext->GetData(kStyleBorderSID);
|
1998-04-14 00:24:54 +04:00
|
|
|
NS_ASSERTION(nsnull!=myColor, "bad style color");
|
1998-04-22 10:37:57 +04:00
|
|
|
NS_ASSERTION(nsnull!=myBorder, "bad style border");
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
|
|
|
|
aDirtyRect, mRect, *myColor);
|
1998-04-30 04:27:59 +04:00
|
|
|
|
1998-04-14 00:24:54 +04:00
|
|
|
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
|
1998-04-22 10:37:57 +04:00
|
|
|
aDirtyRect, mRect, *myBorder, 0);
|
1998-04-30 04:27:59 +04:00
|
|
|
/*
|
|
|
|
printf("painting borders, size = %d %d %d %d\n",
|
|
|
|
myBorder->mSize.left, myBorder->mSize.top,
|
|
|
|
myBorder->mSize.right, myBorder->mSize.bottom);
|
|
|
|
*/
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
// for debug...
|
|
|
|
if (nsIFrame::GetShowFrameBorders()) {
|
|
|
|
aRenderingContext.SetColor(NS_RGB(0,128,128));
|
|
|
|
aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
|
1998-04-17 05:41:24 +04:00
|
|
|
return NS_OK;
|
1998-04-14 00:24:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Align the cell's child frame within the cell
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
void nsTableCellFrame::VerticallyAlignChild(nsIPresContext* aPresContext)
|
1998-04-25 22:48:48 +04:00
|
|
|
{
|
|
|
|
nsStyleSpacing* spacing =
|
|
|
|
(nsStyleSpacing*)mStyleContext->GetData(kStyleSpacingSID);
|
|
|
|
nsStyleText* textStyle =
|
|
|
|
(nsStyleText*)mStyleContext->GetData(kStyleTextSID);
|
1998-04-14 00:24:54 +04:00
|
|
|
|
1998-04-25 22:48:48 +04:00
|
|
|
nscoord topInset = spacing->mBorderPadding.top;
|
|
|
|
nscoord bottomInset = spacing->mBorderPadding.bottom;
|
1998-04-29 03:57:01 +04:00
|
|
|
PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_MIDDLE;
|
|
|
|
if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) {
|
|
|
|
verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue();
|
|
|
|
}
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
nscoord height = mRect.height;
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
nsRect kidRect;
|
|
|
|
mFirstChild->GetRect(kidRect);
|
|
|
|
nscoord childHeight = kidRect.height;
|
|
|
|
|
|
|
|
|
|
|
|
// Vertically align the child
|
|
|
|
nscoord kidYTop = 0;
|
1998-04-28 01:26:48 +04:00
|
|
|
switch (verticalAlignFlags)
|
1998-04-14 00:24:54 +04:00
|
|
|
{
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BASELINE:
|
|
|
|
// Align the child's baseline at the max baseline
|
|
|
|
//kidYTop = aMaxAscent - kidAscent;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TOP:
|
|
|
|
// Align the top of the child frame with the top of the box,
|
|
|
|
// minus the top padding
|
|
|
|
kidYTop = topInset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
|
|
|
|
kidYTop = height - childHeight - bottomInset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
|
|
|
|
kidYTop = height/2 - childHeight/2;
|
|
|
|
}
|
|
|
|
mFirstChild->MoveTo(kidRect.x, kidYTop);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** helper method to get the row span of this frame's content (which must be a cell) */
|
|
|
|
PRInt32 nsTableCellFrame::GetRowSpan()
|
|
|
|
{
|
|
|
|
PRInt32 result = 0;
|
1998-04-17 05:41:24 +04:00
|
|
|
nsTableCell *cellContent = (nsTableCell *)mContent;
|
1998-04-14 00:24:54 +04:00
|
|
|
if (nsnull!=cellContent)
|
|
|
|
{
|
|
|
|
result = cellContent->GetRowSpan();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1998-04-23 21:29:07 +04:00
|
|
|
/** helper method to get the col span of this frame's content (which must be a cell) */
|
|
|
|
PRInt32 nsTableCellFrame::GetColSpan()
|
|
|
|
{
|
|
|
|
PRInt32 result = 0;
|
|
|
|
nsTableCell *cellContent = (nsTableCell *)mContent;
|
|
|
|
if (nsnull!=cellContent)
|
|
|
|
{
|
|
|
|
result = cellContent->GetColSpan();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** helper method to get the col index of this frame's content (which must be a cell) */
|
|
|
|
PRInt32 nsTableCellFrame::GetColIndex()
|
|
|
|
{
|
|
|
|
PRInt32 result = 0;
|
|
|
|
nsTableCell *cellContent = (nsTableCell *)mContent;
|
|
|
|
if (nsnull!=cellContent)
|
|
|
|
{
|
|
|
|
result = cellContent->GetColIndex();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1998-04-14 00:24:54 +04:00
|
|
|
void nsTableCellFrame::CreatePsuedoFrame(nsIPresContext* aPresContext)
|
|
|
|
{
|
|
|
|
// Do we have a prev-in-flow?
|
|
|
|
if (nsnull == mPrevInFlow) {
|
|
|
|
// No, create a column pseudo frame
|
|
|
|
nsBodyFrame::NewFrame(&mFirstChild, mContent, mIndexInParent, this);
|
|
|
|
mChildCount = 1;
|
|
|
|
|
|
|
|
// Resolve style and set the style context
|
|
|
|
nsIStyleContext* styleContext =
|
|
|
|
aPresContext->ResolveStyleContextFor(mContent, this); // styleContext: ADDREF++
|
|
|
|
mFirstChild->SetStyleContext(styleContext);
|
|
|
|
NS_RELEASE(styleContext); // styleContext: ADDREF--
|
|
|
|
} else {
|
|
|
|
nsTableCellFrame* prevFrame = (nsTableCellFrame *)mPrevInFlow;
|
|
|
|
|
|
|
|
nsIFrame* prevPseudoFrame = prevFrame->mFirstChild;
|
|
|
|
NS_ASSERTION(prevFrame->ChildIsPseudoFrame(prevPseudoFrame), "bad previous pseudo-frame");
|
|
|
|
|
|
|
|
// Create a continuing column
|
1998-04-17 05:41:24 +04:00
|
|
|
prevPseudoFrame->CreateContinuingFrame(aPresContext, this, mFirstChild);
|
1998-04-14 00:24:54 +04:00
|
|
|
mChildCount = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
1998-04-17 05:41:24 +04:00
|
|
|
NS_METHOD nsTableCellFrame::ResizeReflow(nsIPresContext* aPresContext,
|
|
|
|
nsReflowMetrics& aDesiredSize,
|
|
|
|
const nsSize& aMaxSize,
|
|
|
|
nsSize* aMaxElementSize,
|
|
|
|
ReflowStatus& aStatus)
|
1998-04-14 00:24:54 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull!=aPresContext, "bad arg");
|
|
|
|
|
|
|
|
#ifdef NS_DEBUG
|
|
|
|
//PreReflowCheck();
|
|
|
|
#endif
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
aStatus = frComplete;
|
1998-04-14 00:24:54 +04:00
|
|
|
if (gsDebug==PR_TRUE)
|
|
|
|
printf("nsTableCellFrame::ResizeReflow: maxSize=%d,%d\n",
|
|
|
|
aMaxSize.width, aMaxSize.height);
|
|
|
|
|
|
|
|
mFirstContentOffset = mLastContentOffset = 0;
|
|
|
|
|
|
|
|
nsSize availSize(aMaxSize);
|
|
|
|
nsSize maxElementSize;
|
|
|
|
nsSize *pMaxElementSize = aMaxElementSize;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE==aMaxSize.width)
|
|
|
|
pMaxElementSize = &maxElementSize;
|
|
|
|
nsReflowMetrics kidSize;
|
|
|
|
nscoord x = 0;
|
|
|
|
// SEC: what about ascent and decent???
|
|
|
|
|
|
|
|
// Compute the insets (sum of border and padding)
|
1998-04-25 22:48:48 +04:00
|
|
|
nsStyleSpacing* spacing =
|
|
|
|
(nsStyleSpacing*)mStyleContext->GetData(kStyleSpacingSID);
|
|
|
|
nscoord topInset = spacing->mBorderPadding.top;
|
|
|
|
nscoord rightInset = spacing->mBorderPadding.right;
|
|
|
|
nscoord bottomInset = spacing->mBorderPadding.bottom;
|
|
|
|
nscoord leftInset = spacing->mBorderPadding.left;
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
// reduce available space by insets
|
|
|
|
if (NS_UNCONSTRAINEDSIZE!=availSize.width)
|
|
|
|
availSize.width -= leftInset+rightInset;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE!=availSize.height)
|
|
|
|
availSize.height -= topInset+bottomInset;
|
|
|
|
|
|
|
|
mLastContentIsComplete = PR_TRUE;
|
|
|
|
|
|
|
|
// get frame, creating one if needed
|
|
|
|
if (nsnull==mFirstChild)
|
|
|
|
{
|
|
|
|
CreatePsuedoFrame(aPresContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to reflow the child into the available space. It might not
|
|
|
|
// fit or might need continuing.
|
1998-04-23 21:29:07 +04:00
|
|
|
if (availSize.height < 0)
|
|
|
|
availSize.height = 1;
|
1998-04-14 00:24:54 +04:00
|
|
|
nsSize maxKidElementSize;
|
|
|
|
if (gsDebug==PR_TRUE)
|
|
|
|
printf(" nsTableCellFrame::ResizeReflow calling ReflowChild with availSize=%d,%d\n",
|
|
|
|
availSize.width, availSize.height);
|
1998-04-17 05:41:24 +04:00
|
|
|
aStatus = ReflowChild(mFirstChild, aPresContext, kidSize, availSize, pMaxElementSize);
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
if (gsDebug==PR_TRUE)
|
|
|
|
{
|
|
|
|
if (nsnull!=pMaxElementSize)
|
|
|
|
printf(" nsTableCellFrame::ResizeReflow: child returned desiredSize=%d,%d,\
|
|
|
|
and maxElementSize=%d,%d\n",
|
|
|
|
kidSize.width, kidSize.height,
|
|
|
|
pMaxElementSize->width, pMaxElementSize->height);
|
|
|
|
else
|
|
|
|
printf(" nsTableCellFrame::ResizeReflow: child returned desiredSize=%d,%d,\
|
|
|
|
and maxElementSize=nsnull\n",
|
|
|
|
kidSize.width, kidSize.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetFirstContentOffset(mFirstChild);
|
|
|
|
if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@
|
|
|
|
SetLastContentOffset(mFirstChild);
|
|
|
|
if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@
|
|
|
|
|
|
|
|
// Place the child since some of it's content fit in us.
|
|
|
|
mFirstChild->SetRect(nsRect(leftInset + x, topInset,
|
|
|
|
kidSize.width, kidSize.height));
|
|
|
|
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return our size and our result
|
|
|
|
PRInt32 kidWidth = kidSize.width;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE!=kidSize.width) //&& NS_UNCONSTRAINEDSIZE!=aMaxSize.width)
|
|
|
|
kidWidth += leftInset + rightInset;
|
|
|
|
PRInt32 kidHeight = kidSize.height;
|
|
|
|
|
|
|
|
// height can be set w/o being restricted by aMaxSize.height
|
|
|
|
if (NS_UNCONSTRAINEDSIZE!=kidSize.height)
|
|
|
|
kidHeight += topInset + bottomInset;
|
|
|
|
aDesiredSize.width = kidWidth;
|
|
|
|
aDesiredSize.height = kidHeight;
|
|
|
|
aDesiredSize.ascent = topInset;
|
|
|
|
aDesiredSize.descent = bottomInset;
|
|
|
|
|
|
|
|
if (nsnull!=aMaxElementSize)
|
1998-04-21 02:49:15 +04:00
|
|
|
{
|
1998-04-14 00:24:54 +04:00
|
|
|
*aMaxElementSize = *pMaxElementSize;
|
1998-04-21 02:49:15 +04:00
|
|
|
aMaxElementSize->height += topInset + bottomInset;
|
|
|
|
aMaxElementSize->width += leftInset + rightInset;
|
|
|
|
}
|
1998-04-14 00:24:54 +04:00
|
|
|
|
|
|
|
if (gsDebug==PR_TRUE)
|
|
|
|
printf(" nsTableCellFrame::ResizeReflow returning aDesiredSize=%d,%d\n",
|
|
|
|
aDesiredSize.width, aDesiredSize.height);
|
|
|
|
|
|
|
|
#ifdef NS_DEBUG
|
|
|
|
//PostReflowCheck(result);
|
|
|
|
#endif
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
return NS_OK;
|
1998-04-14 00:24:54 +04:00
|
|
|
}
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
NS_METHOD nsTableCellFrame::IncrementalReflow(nsIPresContext* aPresContext,
|
|
|
|
nsReflowMetrics& aDesiredSize,
|
|
|
|
const nsSize& aMaxSize,
|
|
|
|
nsReflowCommand& aReflowCommand,
|
|
|
|
ReflowStatus& aStatus)
|
1998-04-14 00:24:54 +04:00
|
|
|
{
|
|
|
|
if (gsDebug == PR_TRUE) printf("nsTableCellFrame::IncrementalReflow\n");
|
|
|
|
// total hack for now, just some hard-coded values
|
1998-04-17 05:41:24 +04:00
|
|
|
ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull, aStatus);
|
|
|
|
return NS_OK;
|
1998-04-14 00:24:54 +04:00
|
|
|
}
|
|
|
|
|
1998-04-17 05:41:24 +04:00
|
|
|
NS_METHOD nsTableCellFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIFrame*& aContinuingFrame)
|
1998-04-14 00:24:54 +04:00
|
|
|
{
|
|
|
|
nsTableCellFrame* cf = new nsTableCellFrame(mContent, mIndexInParent, aParent);
|
|
|
|
PrepareContinuingFrame(aPresContext, aParent, cf);
|
1998-04-17 05:41:24 +04:00
|
|
|
aContinuingFrame = cf;
|
|
|
|
return NS_OK;
|
1998-04-14 00:24:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----- static methods ----- */
|
|
|
|
|
|
|
|
nsresult nsTableCellFrame::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 nsTableCellFrame(aContent, aIndexInParent, aParent);
|
|
|
|
if (nsnull == it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
*aInstancePtrResult = it;
|
|
|
|
return NS_OK;
|
|
|
|
}
|