Space optimization. mBorderEdges is no longer an embedded object. Now it's allocated when needed (for collapsing border model tables only). This saves 80 bytes per table cell frame for the normal HTML case of adjacent border model git-svn-id: svn://10.0.0.236/trunk@50941 18797224-902f-48f8-a5cc-f745e15eee43
1164 lines
38 KiB
C++
1164 lines
38 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.
|
|
*/
|
|
#include "nsTableCellFrame.h"
|
|
#include "nsTableColFrame.h"
|
|
#include "nsTableFrame.h"
|
|
#include "nsIReflowCommand.h"
|
|
#include "nsIStyleContext.h"
|
|
#include "nsStyleConsts.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIRenderingContext.h"
|
|
#include "nsCSSRendering.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIHTMLContent.h"
|
|
#include "nsHTMLIIDs.h"
|
|
#include "nsHTMLParts.h"
|
|
#include "nsHTMLValue.h"
|
|
#include "nsHTMLAtoms.h"
|
|
#include "nsHTMLIIDs.h"
|
|
#include "nsVoidArray.h"
|
|
#include "nsIPtr.h"
|
|
#include "nsIView.h"
|
|
#include "nsStyleUtil.h"
|
|
#include "nsLayoutAtoms.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIHTMLTableCellElement.h"
|
|
#include "nsIDOMHTMLTableCellElement.h"
|
|
|
|
NS_DEF_PTR(nsIStyleContext);
|
|
static NS_DEFINE_IID(kIHTMLTableCellElementIID, NS_IHTMLTABLECELLELEMENT_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLTableCellElementIID, NS_IDOMHTMLTABLECELLELEMENT_IID);
|
|
|
|
nsTableCellFrame::~nsTableCellFrame()
|
|
{
|
|
delete mBorderEdges;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::Init(nsIPresContext& aPresContext,
|
|
nsIContent* aContent,
|
|
nsIFrame* aParent,
|
|
nsIStyleContext* aContext,
|
|
nsIFrame* aPrevInFlow)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Let the base class do its initialization
|
|
rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext,
|
|
aPrevInFlow);
|
|
|
|
if (aPrevInFlow) {
|
|
// Set the column index
|
|
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
|
|
PRInt32 baseColIndex;
|
|
|
|
cellFrame->GetColIndex(baseColIndex);
|
|
InitCellFrame(baseColIndex);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void nsTableCellFrame::SetPass1MaxElementSize(const nsSize& aMaxElementSize)
|
|
{
|
|
mPass1MaxElementSize.height = aMaxElementSize.height;
|
|
nscoord maxElemWidth = aMaxElementSize.width;
|
|
// the max elem width needs to be set to the max of aMaxElementSize.width and
|
|
// the width attribute if both nowrap and width are present on the cell.
|
|
const nsStylePosition* stylePosition;
|
|
GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)stylePosition));
|
|
if (stylePosition->mWidth.GetUnit() == eStyleUnit_Coord) {
|
|
nscoord styleWidth = stylePosition->mWidth.GetCoordValue();
|
|
if (styleWidth > 0) {
|
|
nsIDOMHTMLTableCellElement* cellContent = nsnull;
|
|
nsresult rv = mContent->QueryInterface(kIDOMHTMLTableCellElementIID, (void **)&cellContent);
|
|
if (cellContent && NS_SUCCEEDED(rv)) {
|
|
PRBool nowrap = PR_FALSE;
|
|
cellContent->GetNoWrap(&nowrap);
|
|
if (nowrap) {
|
|
maxElemWidth = PR_MAX(maxElemWidth, styleWidth);
|
|
}
|
|
NS_RELEASE(cellContent);
|
|
}
|
|
}
|
|
}
|
|
mPass1MaxElementSize.width = maxElemWidth;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::AppendFrames(nsIPresContext& aPresContext,
|
|
nsIPresShell& aPresShell,
|
|
nsIAtom* aListName,
|
|
nsIFrame* aFrameList)
|
|
{
|
|
NS_PRECONDITION(PR_FALSE, "unsupported operation");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::InsertFrames(nsIPresContext& aPresContext,
|
|
nsIPresShell& aPresShell,
|
|
nsIAtom* aListName,
|
|
nsIFrame* aPrevFrame,
|
|
nsIFrame* aFrameList)
|
|
{
|
|
NS_PRECONDITION(PR_FALSE, "unsupported operation");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::RemoveFrame(nsIPresContext& aPresContext,
|
|
nsIPresShell& aPresShell,
|
|
nsIAtom* aListName,
|
|
nsIFrame* aOldFrame)
|
|
{
|
|
NS_PRECONDITION(PR_FALSE, "unsupported operation");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex)
|
|
{
|
|
NS_PRECONDITION(0<=aColIndex, "bad col index arg");
|
|
SetColIndex(aColIndex); // this also sets the contents col index
|
|
nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly
|
|
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
|
|
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
|
|
{
|
|
if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle())
|
|
{
|
|
mBorderEdges = new nsBorderEdges;
|
|
mBorderEdges->mOutsideEdge=PR_FALSE;
|
|
|
|
PRInt32 rowspan = GetRowSpan();
|
|
PRInt32 i;
|
|
for (i=0; i<rowspan; i++)
|
|
{
|
|
nsBorderEdge *borderToAdd = new nsBorderEdge();
|
|
mBorderEdges->mEdges[NS_SIDE_LEFT].AppendElement(borderToAdd);
|
|
borderToAdd = new nsBorderEdge();
|
|
mBorderEdges->mEdges[NS_SIDE_RIGHT].AppendElement(borderToAdd);
|
|
}
|
|
PRInt32 colspan = GetColSpan();
|
|
for (i=0; i<colspan; i++)
|
|
{
|
|
nsBorderEdge *borderToAdd = new nsBorderEdge();
|
|
mBorderEdges->mEdges[NS_SIDE_TOP].AppendElement(borderToAdd);
|
|
borderToAdd = new nsBorderEdge();
|
|
mBorderEdges->mEdges[NS_SIDE_BOTTOM].AppendElement(borderToAdd);
|
|
}
|
|
}
|
|
mCollapseOffset = nsPoint(0,0);
|
|
}
|
|
}
|
|
|
|
nsresult nsTableCellFrame::SetColIndex(PRInt32 aColIndex)
|
|
{
|
|
mColIndex = aColIndex;
|
|
// for style context optimization, set the content's column index if possible.
|
|
// this can only be done if we really have an nsTableCell.
|
|
// other tags mapped to table cell display won't benefit from this optimization
|
|
// see nsHTMLStyleSheet::RulesMatching
|
|
|
|
//nsIContent* cell;
|
|
//kidFrame->GetContent(&cell);
|
|
nsCOMPtr<nsIContent> cell;
|
|
nsresult rv = GetContent(getter_AddRefs(cell));
|
|
if (NS_FAILED(rv) || !cell)
|
|
return rv;
|
|
|
|
nsIHTMLTableCellElement* cellContent = nsnull;
|
|
rv = cell->QueryInterface(kIHTMLTableCellElementIID,
|
|
(void **)&cellContent); // cellContent: REFCNT++
|
|
if (cellContent && NS_SUCCEEDED(rv)) { // it's a table cell
|
|
cellContent->SetColIndex(aColIndex);
|
|
NS_RELEASE(cellContent);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
void nsTableCellFrame::SetBorderEdgeLength(PRUint8 aSide,
|
|
PRInt32 aIndex,
|
|
nscoord aLength)
|
|
{
|
|
NS_PRECONDITION(mBorderEdges, "haven't allocated border edges struct");
|
|
if ((NS_SIDE_LEFT==aSide) || (NS_SIDE_RIGHT==aSide))
|
|
{
|
|
PRInt32 baseRowIndex;
|
|
GetRowIndex(baseRowIndex);
|
|
PRInt32 rowIndex = aIndex-baseRowIndex;
|
|
nsBorderEdge *border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(rowIndex));
|
|
border->mLength = aLength;
|
|
}
|
|
else {
|
|
NS_ASSERTION(PR_FALSE, "bad arg aSide passed to SetBorderEdgeLength");
|
|
}
|
|
}
|
|
|
|
|
|
NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect,
|
|
nsFramePaintLayer aWhichLayer)
|
|
{
|
|
const nsStyleDisplay* disp =
|
|
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
|
|
|
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
|
if (disp->mVisible) {
|
|
const nsStyleColor* myColor =
|
|
(const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
|
|
const nsStyleSpacing* mySpacing =
|
|
(const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing);
|
|
NS_ASSERTION(nsnull!=myColor, "bad style color");
|
|
NS_ASSERTION(nsnull!=mySpacing, "bad style spacing");
|
|
|
|
const nsStyleTable* cellTableStyle;
|
|
GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)cellTableStyle));
|
|
nsRect rect(0, 0, mRect.width, mRect.height);
|
|
|
|
// only non empty cells render their background
|
|
if (PR_FALSE == GetContentEmpty()) {
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
|
|
aDirtyRect, rect, *myColor, *mySpacing, 0, 0);
|
|
}
|
|
|
|
// empty cells do not render their border
|
|
PRBool renderBorder = PR_TRUE;
|
|
if (PR_TRUE==GetContentEmpty())
|
|
{
|
|
if (NS_STYLE_TABLE_EMPTY_CELLS_HIDE==cellTableStyle->mEmptyCells)
|
|
renderBorder=PR_FALSE;
|
|
}
|
|
if (PR_TRUE==renderBorder)
|
|
{
|
|
PRIntn skipSides = GetSkipSides();
|
|
nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly
|
|
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
|
|
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
|
|
{
|
|
const nsStyleTable* tableStyle;
|
|
tableFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)tableStyle));
|
|
if (NS_STYLE_BORDER_SEPARATE == tableFrame->GetBorderCollapseStyle())
|
|
{
|
|
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
|
|
aDirtyRect, rect, *mySpacing, mStyleContext, skipSides);
|
|
}
|
|
else
|
|
{
|
|
nsCSSRendering::PaintBorderEdges(aPresContext, aRenderingContext, this,
|
|
aDirtyRect, rect, mBorderEdges, mStyleContext, skipSides);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// for debug...
|
|
if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
|
|
aRenderingContext.SetColor(NS_RGB(0, 0, 128));
|
|
aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
|
|
}
|
|
|
|
// if the cell originates in a row and/or col that is collapsed, the
|
|
// bottom and/or right portion of the cell is painted by translating
|
|
// the rendering context.
|
|
PRBool clipState;
|
|
aRenderingContext.PushState();
|
|
nsPoint offset = mCollapseOffset;
|
|
if ((0 != offset.x) || (0 != offset.y)) {
|
|
aRenderingContext.Translate(offset.x, offset.y);
|
|
}
|
|
// Bug 6674 is fixed by uncommenting the following if statement, but sample 4 resizing
|
|
// of the collapsed table rows then paints incorrectly
|
|
//if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) {
|
|
aRenderingContext.SetClipRect(nsRect(-offset.x, -offset.y, mRect.width, mRect.height),
|
|
nsClipCombine_kIntersect, clipState);
|
|
//}
|
|
PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
|
|
aRenderingContext.PopState(clipState);
|
|
|
|
return NS_OK;
|
|
/*nsFrame::Paint(aPresContext,
|
|
aRenderingContext,
|
|
aDirtyRect,
|
|
aWhichLayer);*/
|
|
}
|
|
|
|
//null range means the whole thing
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::SetSelected(nsIDOMRange *aRange,PRBool aSelected, nsSpread aSpread)
|
|
{
|
|
//traverse through children unselect tables
|
|
#if 0
|
|
if ((aSpread == eSpreadDown)){
|
|
nsIFrame* kid;
|
|
FirstChild(nsnull, &kid);
|
|
while (nsnull != kid) {
|
|
kid->SetSelected(nsnull,aSelected,eSpreadDown);
|
|
|
|
kid->GetNextSibling(&kid);
|
|
}
|
|
}
|
|
//return nsFrame::SetSelected(aRange,aSelected,eSpreadNone);
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
PRIntn
|
|
nsTableCellFrame::GetSkipSides() const
|
|
{
|
|
PRIntn skip = 0;
|
|
if (nsnull != mPrevInFlow) {
|
|
skip |= 1 << NS_SIDE_TOP;
|
|
}
|
|
if (nsnull != mNextInFlow) {
|
|
skip |= 1 << NS_SIDE_BOTTOM;
|
|
}
|
|
return skip;
|
|
}
|
|
|
|
PRBool nsTableCellFrame::ParentDisablesSelection() const //override default behavior
|
|
{
|
|
PRBool returnval;
|
|
if (NS_FAILED(GetSelected(&returnval)))
|
|
return PR_FALSE;
|
|
if (returnval)
|
|
return PR_TRUE;
|
|
return nsFrame::ParentDisablesSelection();
|
|
}
|
|
|
|
void nsTableCellFrame::SetBorderEdge(PRUint8 aSide,
|
|
PRInt32 aRowIndex,
|
|
PRInt32 aColIndex,
|
|
nsBorderEdge *aBorder,
|
|
nscoord aOddAmountToAdd)
|
|
{
|
|
NS_PRECONDITION(mBorderEdges, "haven't allocated border edges struct");
|
|
nsBorderEdge *border = nsnull;
|
|
switch (aSide)
|
|
{
|
|
case NS_SIDE_TOP:
|
|
{
|
|
PRInt32 baseColIndex;
|
|
GetColIndex(baseColIndex);
|
|
PRInt32 colIndex = aColIndex-baseColIndex;
|
|
border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(colIndex));
|
|
mBorderEdges->mMaxBorderWidth.top = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.top);
|
|
break;
|
|
}
|
|
|
|
case NS_SIDE_BOTTOM:
|
|
{
|
|
PRInt32 baseColIndex;
|
|
GetColIndex(baseColIndex);
|
|
PRInt32 colIndex = aColIndex-baseColIndex;
|
|
border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(colIndex));
|
|
mBorderEdges->mMaxBorderWidth.bottom = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.bottom);
|
|
break;
|
|
}
|
|
|
|
case NS_SIDE_LEFT:
|
|
{
|
|
PRInt32 baseRowIndex;
|
|
GetRowIndex(baseRowIndex);
|
|
PRInt32 rowIndex = aRowIndex-baseRowIndex;
|
|
border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(rowIndex));
|
|
mBorderEdges->mMaxBorderWidth.left = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.left);
|
|
break;
|
|
}
|
|
|
|
case NS_SIDE_RIGHT:
|
|
{
|
|
PRInt32 baseRowIndex;
|
|
GetRowIndex(baseRowIndex);
|
|
PRInt32 rowIndex = aRowIndex-baseRowIndex;
|
|
border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(rowIndex));
|
|
mBorderEdges->mMaxBorderWidth.right = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.right);
|
|
break;
|
|
}
|
|
}
|
|
if (nsnull!=border) {
|
|
*border=*aBorder;
|
|
border->mWidth += aOddAmountToAdd;
|
|
}
|
|
else {
|
|
NS_ASSERTION(PR_FALSE, "bad border edge state");
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Align the cell's child frame within the cell
|
|
*
|
|
*/
|
|
void nsTableCellFrame::VerticallyAlignChild()
|
|
{
|
|
const nsStyleSpacing* spacing =
|
|
(const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing);
|
|
const nsStyleText* textStyle =
|
|
(const nsStyleText*)mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
/* XXX: remove tableFrame when border-collapse inherits */
|
|
nsTableFrame* tableFrame=nsnull;
|
|
(void) nsTableFrame::GetTableFrame(this, tableFrame);
|
|
nsMargin borderPadding;
|
|
GetCellBorder (borderPadding, tableFrame);
|
|
nsMargin padding;
|
|
spacing->GetPadding(padding);
|
|
borderPadding += padding;
|
|
|
|
nscoord topInset = borderPadding.top;
|
|
nscoord bottomInset = borderPadding.bottom;
|
|
PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_MIDDLE;
|
|
if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) {
|
|
verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue();
|
|
}
|
|
nscoord height = mRect.height;
|
|
nsRect kidRect;
|
|
nsIFrame* firstKid = mFrames.FirstChild();
|
|
firstKid->GetRect(kidRect);
|
|
nscoord childHeight = kidRect.height;
|
|
|
|
|
|
// Vertically align the child
|
|
nscoord kidYTop = 0;
|
|
switch (verticalAlignFlags)
|
|
{
|
|
case NS_STYLE_VERTICAL_ALIGN_BASELINE:
|
|
// Align the baselines of the child frame with the baselines of
|
|
// other children in the same row which have align = baseline
|
|
// XXX Not yet implemented, so fall through to top
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TOP:
|
|
// Align the top of the child frame with the top of the content area,
|
|
kidYTop = topInset;
|
|
break;
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
|
|
// Align the bottom of the child frame with the bottom of the content area,
|
|
kidYTop = height - childHeight - bottomInset;
|
|
break;
|
|
|
|
default:
|
|
case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
|
|
// Align the middle of the child frame with the middle of the content area,
|
|
kidYTop = (height - childHeight - bottomInset + topInset) / 2;
|
|
}
|
|
firstKid->MoveTo(kidRect.x, kidYTop);
|
|
}
|
|
|
|
PRInt32 nsTableCellFrame::GetRowSpan()
|
|
{
|
|
PRInt32 rowSpan=1;
|
|
nsIHTMLContent *hc=nsnull;
|
|
nsresult rv = mContent->QueryInterface(kIHTMLContentIID, (void**) &hc);
|
|
if (NS_OK==rv)
|
|
{
|
|
nsHTMLValue val;
|
|
hc->GetHTMLAttribute(nsHTMLAtoms::rowspan, val);
|
|
if (eHTMLUnit_Integer == val.GetUnit()) {
|
|
rowSpan=val.GetIntValue();
|
|
}
|
|
NS_RELEASE(hc);
|
|
}
|
|
return rowSpan;
|
|
}
|
|
|
|
PRInt32 nsTableCellFrame::GetColSpan()
|
|
{
|
|
PRInt32 colSpan=1;
|
|
nsIHTMLContent *hc=nsnull;
|
|
nsresult rv = mContent->QueryInterface(kIHTMLContentIID, (void**) &hc);
|
|
if (NS_OK==rv)
|
|
{
|
|
nsHTMLValue val;
|
|
hc->GetHTMLAttribute(nsHTMLAtoms::colspan, val);
|
|
if (eHTMLUnit_Integer == val.GetUnit()) {
|
|
colSpan=val.GetIntValue();
|
|
}
|
|
NS_RELEASE(hc);
|
|
}
|
|
return colSpan;
|
|
}
|
|
|
|
|
|
static
|
|
void DebugCheckChildSize(nsIFrame* aChild,
|
|
nsHTMLReflowMetrics& aMet,
|
|
nsSize& aAvailSize,
|
|
PRBool aIsPass2Reflow)
|
|
{
|
|
|
|
/* approved for commenting out by rickg
|
|
if (aMet.width > aAvailSize.width) {
|
|
nsAutoString tmp;
|
|
aChild->GetFrameName(tmp);
|
|
printf("WARNING: cell ");
|
|
fputs(tmp, stdout);
|
|
printf(" content has desired width %d given avail width %d\n",
|
|
aMet.width, aAvailSize.width);
|
|
}
|
|
*/
|
|
if (aIsPass2Reflow) {
|
|
if ((aMet.width < 0) || (aMet.width > 60000)) {
|
|
printf("WARNING: cell content %p has large width %d \n", aChild, aMet.width);
|
|
}
|
|
if ((aMet.height < 0) || (aMet.height > 60000)) {
|
|
printf("WARNING: cell content %p has large height %d \n", aChild, aMet.height);
|
|
}
|
|
}
|
|
if (aMet.maxElementSize) {
|
|
nscoord tmp = aMet.maxElementSize->width;
|
|
if ((tmp < 0) || (tmp > 60000)) {
|
|
printf("WARNING: cell content %p has large max element width %d \n", aChild, tmp);
|
|
}
|
|
tmp = aMet.maxElementSize->height;
|
|
if ((tmp < 0) || (tmp > 60000)) {
|
|
printf("WARNING: cell content %p has large max element height %d \n", aChild, tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext,
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus)
|
|
{
|
|
if (nsDebugTable::gRflCell) nsTableFrame::DebugReflow("TC::Rfl", this, &aReflowState, nsnull);
|
|
|
|
nsresult rv = NS_OK;
|
|
// this should probably be cached somewhere
|
|
nsCompatibility compatMode;
|
|
aPresContext.GetCompatibilityMode(&compatMode);
|
|
|
|
// Initialize out parameter
|
|
if (nsnull != aDesiredSize.maxElementSize) {
|
|
aDesiredSize.maxElementSize->width = 0;
|
|
aDesiredSize.maxElementSize->height = 0;
|
|
}
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight);
|
|
nsSize maxElementSize;
|
|
nsSize *pMaxElementSize = aDesiredSize.maxElementSize;
|
|
if (NS_UNCONSTRAINEDSIZE==aReflowState.availableWidth)
|
|
pMaxElementSize = &maxElementSize;
|
|
|
|
// SEC: what about ascent and decent???
|
|
|
|
// Compute the insets (sum of border and padding)
|
|
const nsStyleSpacing* spacing =
|
|
(const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing);
|
|
|
|
/* XXX: remove tableFrame when border-collapse inherits */
|
|
nsTableFrame* tableFrame=nsnull;
|
|
rv = nsTableFrame::GetTableFrame(this, tableFrame);
|
|
nsMargin padding;
|
|
spacing->GetPadding(padding);
|
|
nsMargin borderPadding = padding;
|
|
nsMargin border;
|
|
GetCellBorder(border, tableFrame);
|
|
if ((NS_UNCONSTRAINEDSIZE == availSize.width) || !GetContentEmpty()) {
|
|
borderPadding += border;
|
|
}
|
|
|
|
nscoord topInset = borderPadding.top;
|
|
nscoord rightInset = borderPadding.right;
|
|
nscoord bottomInset = borderPadding.bottom;
|
|
nscoord leftInset = borderPadding.left;
|
|
|
|
// reduce available space by insets, if we're in a constrained situation
|
|
if (NS_UNCONSTRAINEDSIZE!=availSize.width)
|
|
availSize.width -= leftInset+rightInset;
|
|
if (NS_UNCONSTRAINEDSIZE!=availSize.height)
|
|
availSize.height -= topInset+bottomInset;
|
|
|
|
PRBool isStyleChanged = PR_FALSE;
|
|
if (eReflowReason_Incremental == aReflowState.reason)
|
|
{
|
|
// We *must* do this otherwise incremental reflow that's
|
|
// passing through will not work right.
|
|
nsIFrame* next;
|
|
aReflowState.reflowCommand->GetNext(next);
|
|
|
|
// if it is a StyleChanged reflow targeted at this cell frame,
|
|
// handle that here
|
|
// first 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)
|
|
{
|
|
nsIReflowCommand::ReflowType type;
|
|
aReflowState.reflowCommand->GetType(type);
|
|
if (nsIReflowCommand::StyleChanged==type)
|
|
{
|
|
isStyleChanged = PR_TRUE;
|
|
}
|
|
else {
|
|
NS_ASSERTION(PR_FALSE, "table cell target of illegal incremental reflow type");
|
|
}
|
|
}
|
|
}
|
|
// if any of these conditions are not true, we just pass the reflow command down
|
|
}
|
|
|
|
// Try to reflow the child into the available space. It might not
|
|
// fit or might need continuing.
|
|
if (availSize.height < 0)
|
|
availSize.height = 1;
|
|
|
|
nsHTMLReflowMetrics kidSize(pMaxElementSize);
|
|
kidSize.width=kidSize.height=kidSize.ascent=kidSize.descent=0;
|
|
SetPriorAvailWidth(aReflowState.availableWidth);
|
|
nsIFrame* firstKid = mFrames.FirstChild();
|
|
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
|
|
availSize);
|
|
|
|
// If it was a style change targeted at us, then reflow the child using
|
|
// the special reflow reason
|
|
if (isStyleChanged) {
|
|
kidReflowState.reason = eReflowReason_StyleChange;
|
|
kidReflowState.reflowCommand = nsnull;
|
|
}
|
|
|
|
if (nsDebugTable::gRflArea) nsTableFrame::DebugReflow("Area::Rfl en", firstKid, &kidReflowState, nsnull);
|
|
ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, aStatus);
|
|
if (nsDebugTable::gRflArea) nsTableFrame::DebugReflow("Area::Rfl ex", firstKid, nsnull, &kidSize);
|
|
|
|
#ifdef NS_DEBUG
|
|
DebugCheckChildSize(firstKid, kidSize, availSize, (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth));
|
|
#endif
|
|
|
|
PRBool useInsets = PR_TRUE;
|
|
// 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
|
|
// see testcase "emptyCells.html"
|
|
if (NS_UNCONSTRAINEDSIZE == kidReflowState.availableWidth) {
|
|
if ((0 == kidSize.width) || (0 == kidSize.height)) {
|
|
//if ((0 == kidSize.width) && (0 == kidSize.height)) { // XXX why was this &&
|
|
SetContentEmpty(PR_TRUE);
|
|
useInsets = PR_FALSE;
|
|
// need to reduce the insets by border if the cell is empty
|
|
leftInset -= border.left;
|
|
rightInset -= border.right;
|
|
topInset -= border.top;
|
|
bottomInset -= border.bottom;
|
|
}
|
|
else
|
|
SetContentEmpty(PR_FALSE);
|
|
}
|
|
|
|
const nsStylePosition* pos;
|
|
GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)pos));
|
|
|
|
// calculate the min cell width
|
|
float p2t;
|
|
aPresContext.GetScaledPixelsToTwips(&p2t);
|
|
nscoord onePixel = NSIntPixelsToTwips(1, p2t);
|
|
nscoord smallestMinWidth = onePixel;
|
|
if (eCompatibility_NavQuirks == compatMode) {
|
|
if ((pos->mWidth.GetUnit() != eStyleUnit_Coord) &&
|
|
(pos->mWidth.GetUnit() != eStyleUnit_Percent)) {
|
|
if (border.left > 0)
|
|
smallestMinWidth += onePixel;
|
|
if (border.right > 0)
|
|
smallestMinWidth += onePixel;
|
|
}
|
|
}
|
|
PRInt32 colspan = GetColSpan();
|
|
if (colspan > 1) {
|
|
smallestMinWidth = PR_MAX(smallestMinWidth, colspan * onePixel);
|
|
nscoord spacingX = tableFrame->GetCellSpacingX();
|
|
nscoord spacingExtra = spacingX * (colspan - 1);
|
|
smallestMinWidth += spacingExtra;
|
|
if (padding.left > 0) {
|
|
smallestMinWidth -= onePixel;
|
|
}
|
|
}
|
|
|
|
if ((0 == kidSize.width) && (NS_UNCONSTRAINEDSIZE != kidReflowState.availableWidth)) {
|
|
// empty content has to be forced to the assigned width for resize or incremental reflow
|
|
kidSize.width = kidReflowState.availableWidth;
|
|
}
|
|
if (0 == kidSize.height) {
|
|
if ((pos->mHeight.GetUnit() != eStyleUnit_Coord) &&
|
|
(pos->mHeight.GetUnit() != eStyleUnit_Percent)) {
|
|
// Standard mode should probably be 0 pixels high instead of 1
|
|
PRInt32 pixHeight = (eCompatibility_Standard == compatMode) ? 1 : 2;
|
|
kidSize.height = NSIntPixelsToTwips(pixHeight, p2t);
|
|
if ((nsnull != aDesiredSize.maxElementSize) && (0 == pMaxElementSize->height))
|
|
pMaxElementSize->height = kidSize.height;
|
|
}
|
|
}
|
|
// end 0 dimensioned cells
|
|
|
|
kidSize.width = PR_MAX(kidSize.width, smallestMinWidth);
|
|
|
|
// Place the child
|
|
//////////////////////////////// HACK //////////////////////////////
|
|
kidSize.width = PR_MIN(kidSize.width, availSize.width);
|
|
///////////////////////////// END HACK /////////////////////////////
|
|
firstKid->SetRect(nsRect(leftInset, topInset,
|
|
kidSize.width, kidSize.height));
|
|
|
|
// Return our size and our result
|
|
|
|
// first, compute the height which can be set w/o being restricted by aMaxSize.height
|
|
nscoord cellHeight = kidSize.height;
|
|
if (NS_UNCONSTRAINEDSIZE != cellHeight) {
|
|
cellHeight += topInset + bottomInset;
|
|
}
|
|
|
|
// next determine the cell's width
|
|
nscoord cellWidth = kidSize.width; // at this point, we've factored in the cell's style attributes
|
|
|
|
// factor in border and padding
|
|
if (NS_UNCONSTRAINEDSIZE != cellWidth) {
|
|
cellWidth += leftInset + rightInset;
|
|
}
|
|
|
|
// set the cell's desired size and max element size
|
|
aDesiredSize.width = cellWidth;
|
|
aDesiredSize.height = cellHeight;
|
|
aDesiredSize.ascent = topInset;
|
|
aDesiredSize.descent = bottomInset;
|
|
if (nsnull!=aDesiredSize.maxElementSize) {
|
|
*aDesiredSize.maxElementSize = *pMaxElementSize;
|
|
if (0!=pMaxElementSize->height) {
|
|
aDesiredSize.maxElementSize->height += topInset + bottomInset;
|
|
}
|
|
aDesiredSize.maxElementSize->width = PR_MAX(smallestMinWidth, aDesiredSize.maxElementSize->width);
|
|
aDesiredSize.maxElementSize->width += leftInset + rightInset;
|
|
}
|
|
// remember my desired size for this reflow
|
|
SetDesiredSize(aDesiredSize);
|
|
|
|
aDesiredSize.ascent = aDesiredSize.height;
|
|
aDesiredSize.descent = 0;
|
|
|
|
if (nsDebugTable::gRflCell) nsTableFrame::DebugReflow("TC::Rfl ex", this, nsnull, &aDesiredSize);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Update the border style to map to the HTML border style
|
|
*
|
|
*/
|
|
void nsTableCellFrame::MapHTMLBorderStyle(nsIPresContext* aPresContext,
|
|
nsStyleSpacing& aSpacingStyle,
|
|
nsTableFrame* aTableFrame)
|
|
{
|
|
//adjust the border style based on the table rules attribute
|
|
const nsStyleTable* tableStyle;
|
|
aTableFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
|
|
|
|
switch (tableStyle->mRules)
|
|
{
|
|
case NS_STYLE_TABLE_RULES_NONE:
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_NONE);
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_NONE);
|
|
break;
|
|
|
|
case NS_STYLE_TABLE_RULES_COLS:
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
|
|
break;
|
|
|
|
case NS_STYLE_TABLE_RULES_ROWS:
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_NONE);
|
|
aSpacingStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_NONE);
|
|
break;
|
|
|
|
default:
|
|
// do nothing for "GROUPS" or "ALL" or for any illegal value
|
|
// "GROUPS" will be handled in nsTableFrame::ProcessGroupRules
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
PRBool nsTableCellFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult)
|
|
{
|
|
if (aValue.GetUnit() == eHTMLUnit_Pixel)
|
|
aResult = aValue.GetPixelValue();
|
|
else if (aValue.GetUnit() == eHTMLUnit_Empty)
|
|
aResult = aDefault;
|
|
else
|
|
{
|
|
NS_ERROR("Unit must be pixel or empty");
|
|
return PR_FALSE;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
void nsTableCellFrame::MapBorderMarginPadding(nsIPresContext* aPresContext)
|
|
{
|
|
// Check to see if the table has either cell padding or
|
|
// Cell spacing defined for the table. If true, then
|
|
// this setting overrides any specific border, margin or
|
|
// padding information in the cell. If these attributes
|
|
// are not defined, the the cells attributes are used
|
|
|
|
nsTableFrame* tableFrame;
|
|
nsTableFrame::GetTableFrame(this, tableFrame);
|
|
NS_ASSERTION(tableFrame,"Table must not be null");
|
|
if (!tableFrame)
|
|
return;
|
|
|
|
nscoord spacingX = tableFrame->GetCellSpacingX();
|
|
nscoord spacingY = tableFrame->GetCellSpacingY();
|
|
|
|
// get the table frame style context, and from it get cellpadding, cellspacing, and border info
|
|
const nsStyleTable* tableStyle;
|
|
tableFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
|
|
const nsStyleSpacing* tableSpacingStyle;
|
|
tableFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)tableSpacingStyle);
|
|
nsStyleSpacing* spacingData = (nsStyleSpacing*)mStyleContext->GetMutableStyleData(eStyleStruct_Spacing);
|
|
|
|
// Cache the border-spacing into margin and wipe out any previous
|
|
// margins, since CSS doesn't allow margins to be set on cells
|
|
spacingData->mMargin.SetTop(spacingY);
|
|
spacingData->mMargin.SetRight(spacingX);
|
|
spacingData->mMargin.SetBottom(spacingY);
|
|
spacingData->mMargin.SetLeft(spacingX);
|
|
|
|
float p2t;
|
|
aPresContext->GetPixelsToTwips(&p2t);
|
|
|
|
// Get the table's cellpadding or use 2 pixels as the default if it is not set.
|
|
// This assumes that ua.css does not set padding for the cell.
|
|
nscoord defaultPadding = tableFrame->GetCellPadding();
|
|
if (-1 == defaultPadding) { // not set in table
|
|
defaultPadding = NSIntPixelsToTwips(1, p2t);
|
|
}
|
|
|
|
// if the padding is not already set, set it to the table's cellpadding
|
|
if (eStyleUnit_Null == spacingData->mPadding.GetTopUnit())
|
|
spacingData->mPadding.SetTop(defaultPadding);
|
|
if (eStyleUnit_Null == spacingData->mPadding.GetRightUnit())
|
|
spacingData->mPadding.SetRight(defaultPadding);
|
|
if (eStyleUnit_Null == spacingData->mPadding.GetBottomUnit())
|
|
spacingData->mPadding.SetBottom(defaultPadding);
|
|
if (eStyleUnit_Null == spacingData->mPadding.GetLeftUnit())
|
|
spacingData->mPadding.SetLeft(defaultPadding);
|
|
|
|
MapHTMLBorderStyle(aPresContext, *spacingData, tableFrame);
|
|
|
|
MapVAlignAttribute(aPresContext, tableFrame);
|
|
MapHAlignAttribute(aPresContext, tableFrame);
|
|
|
|
}
|
|
|
|
/* XXX: this code will not work properly until the style and layout code has been updated
|
|
* as outlined in Bugzilla bug report 1802 and 915 */
|
|
void nsTableCellFrame::MapVAlignAttribute(nsIPresContext* aPresContext, nsTableFrame *aTableFrame)
|
|
{
|
|
const nsStyleText* textStyle;
|
|
GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)textStyle);
|
|
// check if valign is set on the cell
|
|
// this condition will also be true if we inherited valign from the row or rowgroup
|
|
if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated)
|
|
{
|
|
return; // valign is already set on this cell
|
|
}
|
|
|
|
// check if valign is set on the cell's COL (or COLGROUP by inheritance)
|
|
nsTableColFrame *colFrame;
|
|
PRInt32 colIndex;
|
|
GetColIndex(colIndex);
|
|
aTableFrame->GetColumnFrame(colIndex, colFrame);
|
|
if (colFrame) {
|
|
const nsStyleText* colTextStyle;
|
|
colFrame->GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)colTextStyle);
|
|
if (colTextStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) {
|
|
nsStyleText* mutableTextStyle = (nsStyleText*)mStyleContext->GetMutableStyleData(eStyleStruct_Text);
|
|
mutableTextStyle->mVerticalAlign.SetIntValue(colTextStyle->mVerticalAlign.GetIntValue(), eStyleUnit_Enumerated);
|
|
return; // valign set from COL info
|
|
}
|
|
}
|
|
|
|
// otherwise, set the vertical align attribute to the HTML default
|
|
nsStyleText* mutableTextStyle = (nsStyleText*)mStyleContext->GetMutableStyleData(eStyleStruct_Text);
|
|
mutableTextStyle->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_MIDDLE, eStyleUnit_Enumerated);
|
|
}
|
|
|
|
/* XXX: this code will not work properly until the style and layout code has been updated
|
|
* as outlined in Bugzilla bug report 1802 and 915.
|
|
* In particular, mTextAlign has to be an nsStyleCoord, not just an int */
|
|
void nsTableCellFrame::MapHAlignAttribute(nsIPresContext* aPresContext, nsTableFrame *aTableFrame)
|
|
{
|
|
#if 0
|
|
const nsStyleText* textStyle;
|
|
GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)textStyle);
|
|
// check if halign is set on the cell
|
|
// cells do not inherited halign from the row or rowgroup
|
|
if (textStyle->mTextAlign.GetUnit() == eStyleUnit_Enumerated)
|
|
{
|
|
if (textStyle->mTextAlign.GetIntValue() != NS_STYLE_TEXT_ALIGN_DEFAULT)
|
|
return; // valign is already set on this cell
|
|
}
|
|
|
|
// check if halign is set on the cell's ROW (or ROWGROUP by inheritance)
|
|
nsIFrame *rowFrame;
|
|
aTableFrame->GetContentParent(rowFrame);
|
|
const nsStyleText* rowTextStyle;
|
|
rowFrame->GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)rowTextStyle);
|
|
if (rowTextStyle->mTextAlign.GetUnit() == eStyleUnit_Enumerated)
|
|
{
|
|
nsStyleText* mutableTextStyle = (nsStyleText*)mStyleContext->GetMutableStyleData(eStyleStruct_Text);
|
|
mutableTextStyle->mTextAlign.SetIntValue(rowTextStyle->mTextAlign.GetIntValue(), eStyleUnit_Enumerated);
|
|
return; // halign set from ROW info
|
|
}
|
|
|
|
// check if halign is set on the cell's COL (or COLGROUP by inheritance)
|
|
nsTableColFrame *colFrame;
|
|
PRInt32 colIndex;
|
|
GetColIndex(colIndex);
|
|
aTableFrame->GetColumnFrame(colIndex, colFrame);
|
|
if (colFrame) {
|
|
const nsStyleText* colTextStyle;
|
|
colFrame->GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)colTextStyle);
|
|
if (colTextStyle->mTextAlign.GetUnit() == eStyleUnit_Enumerated)
|
|
{
|
|
nsStyleText* mutableTextStyle = (nsStyleText*)mStyleContext->GetMutableStyleData(eStyleStruct_Text);
|
|
mutableTextStyle->mTextAlign.SetIntValue(colTextStyle->mTextAlign.GetIntValue(), eStyleUnit_Enumerated);
|
|
return; // halign set from COL info
|
|
}
|
|
}
|
|
|
|
// otherwise, set the vertical align attribute to the HTML default (center for TH, left for TD and all others)
|
|
nsStyleText* mutableTextStyle = (nsStyleText*)mStyleContext->GetMutableStyleData(eStyleStruct_Text);
|
|
nsIAtom *tag=nsnull;
|
|
if (nsnull!=mContent)
|
|
mContent->GetTag(tag);
|
|
if (nsHTMLAtoms::th==tag)
|
|
mutableTextStyle->mVerticalAlign.SetIntValue(NS_STYLE_TEXT_ALIGN_CENTER, eStyleUnit_Enumerated);
|
|
else
|
|
mutableTextStyle->mVerticalAlign.SetIntValue(NS_STYLE_TEXT_ALIGN_LEFT, eStyleUnit_Enumerated);
|
|
#endif
|
|
}
|
|
|
|
// Subclass hook for style post processing
|
|
NS_METHOD nsTableCellFrame::DidSetStyleContext(nsIPresContext* aPresContext)
|
|
{
|
|
#ifdef NOISY_STYLE
|
|
printf("nsTableCellFrame::DidSetStyleContext \n");
|
|
#endif
|
|
|
|
MapBorderMarginPadding(aPresContext);
|
|
mStyleContext->RecalcAutomaticData(aPresContext);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* ----- global methods ----- */
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsTableCellFrame, nsHTMLContainerFrame)
|
|
NS_IMPL_RELEASE_INHERITED(nsTableCellFrame, nsHTMLContainerFrame)
|
|
|
|
nsresult nsTableCellFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(nsITableCellLayout::GetIID())) {
|
|
*aInstancePtr = (void*) (nsITableCellLayout *)this;
|
|
return NS_OK;
|
|
} else {
|
|
return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
|
|
}
|
|
}
|
|
|
|
/* This is primarily for editor access via nsITableLayout */
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::GetCellIndexes(PRInt32 &aRowIndex, PRInt32 &aColIndex)
|
|
{
|
|
nsresult res = GetRowIndex(aRowIndex);
|
|
if (NS_FAILED(res))
|
|
{
|
|
aColIndex = 0;
|
|
return res;
|
|
}
|
|
aColIndex = mColIndex;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
NS_NewTableCellFrame(nsIFrame** aNewFrame)
|
|
{
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
if (nsnull == aNewFrame) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
nsTableCellFrame* it = new nsTableCellFrame;
|
|
if (nsnull == it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
*aNewFrame = it;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
/* ----- methods from CellLayoutData ----- */
|
|
|
|
/**
|
|
* Given a frame and an edge, find the margin
|
|
*
|
|
**/
|
|
nscoord nsTableCellFrame::GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const
|
|
{
|
|
nscoord result = 0;
|
|
|
|
if (aFrame)
|
|
{
|
|
const nsStyleSpacing* spacing;
|
|
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
|
|
nsMargin margin;
|
|
spacing->CalcMarginFor(aFrame, margin);
|
|
switch (aEdge)
|
|
{
|
|
case NS_SIDE_TOP:
|
|
result = margin.top;
|
|
break;
|
|
|
|
case NS_SIDE_RIGHT:
|
|
result = margin.right;
|
|
break;
|
|
|
|
case NS_SIDE_BOTTOM:
|
|
result = margin.bottom;
|
|
break;
|
|
|
|
case NS_SIDE_LEFT:
|
|
result = margin.left;
|
|
break;
|
|
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Given an Edge, find the opposing edge (top<-->bottom, left<-->right)
|
|
*
|
|
**/
|
|
PRUint8 nsTableCellFrame::GetOpposingEdge(PRUint8 aEdge)
|
|
{
|
|
PRUint8 result;
|
|
|
|
switch (aEdge)
|
|
{
|
|
case NS_SIDE_LEFT:
|
|
result = NS_SIDE_RIGHT;
|
|
break;
|
|
|
|
case NS_SIDE_RIGHT:
|
|
result = NS_SIDE_LEFT;
|
|
break;
|
|
|
|
case NS_SIDE_TOP:
|
|
result = NS_SIDE_BOTTOM;
|
|
break;
|
|
|
|
case NS_SIDE_BOTTOM:
|
|
result = NS_SIDE_TOP;
|
|
break;
|
|
|
|
default:
|
|
result = NS_SIDE_TOP;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void nsTableCellFrame::GetCellBorder(nsMargin &aBorder, nsTableFrame *aTableFrame)
|
|
{
|
|
aBorder.left = aBorder.right = aBorder.top = aBorder.bottom = 0;
|
|
if (nsnull==aTableFrame) {
|
|
return;
|
|
}
|
|
|
|
if (NS_STYLE_BORDER_COLLAPSE==aTableFrame->GetBorderCollapseStyle()) {
|
|
NS_PRECONDITION(mBorderEdges, "haven't allocated border edges struct");
|
|
aBorder = mBorderEdges->mMaxBorderWidth;
|
|
} else {
|
|
const nsStyleSpacing* spacing;
|
|
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
|
|
spacing->GetBorder(aBorder);
|
|
}
|
|
}
|
|
|
|
void nsTableCellFrame::RecalcLayoutData(nsMargin& aMargin)
|
|
{
|
|
mMargin.left = aMargin.left;
|
|
mMargin.top = aMargin.top;
|
|
mMargin.right = aMargin.right;
|
|
mMargin.bottom = aMargin.bottom;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::GetFrameType(nsIAtom** aType) const
|
|
{
|
|
NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
|
|
*aType = nsLayoutAtoms::tableCellFrame;
|
|
NS_ADDREF(*aType);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::GetFrameName(nsString& aResult) const
|
|
{
|
|
return MakeFrameName("TableCell", aResult);
|
|
}
|
|
|
|
void nsTableCellFrame::SetCollapseOffsetX(nscoord aXOffset)
|
|
{
|
|
mCollapseOffset.x = aXOffset;
|
|
}
|
|
|
|
void nsTableCellFrame::SetCollapseOffsetY(nscoord aYOffset)
|
|
{
|
|
mCollapseOffset.y = aYOffset;
|
|
}
|
|
|
|
nsPoint nsTableCellFrame::GetCollapseOffset()
|
|
{
|
|
return mCollapseOffset;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
NS_IMETHODIMP
|
|
nsTableCellFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
|
|
{
|
|
if (!aResult) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
PRUint32 sum = sizeof(*this);
|
|
*aResult = sum;
|
|
return NS_OK;
|
|
}
|
|
#endif
|