Bug 365151: fix crash [@ nsStyleContext::GetRuleNode] or [@ nsTreeColumn::GetContent] due to stale nsTreeColumn::mFrame, patch by Nickolay Ponomarev <asqueella@gmail.com>, r+sr=roc

This commit is contained in:
gavin%gavinsharp.com 2007-01-09 19:59:38 +00:00
Родитель 69b81fec30
Коммит ee6ecd904c
4 изменённых файлов: 374 добавлений и 176 удалений

Просмотреть файл

@ -288,13 +288,15 @@ nsTreeBodyFrame::CalcMaxRowWidth()
for (PRInt32 row = 0; row < mRowCount; ++row) {
rowWidth = 0;
col = mColumns->GetFirstColumn();
while (col) {
for (col = mColumns->GetFirstColumn(); col; col = col->GetNext()) {
nscoord desiredWidth, currentWidth;
GetCellWidth(row, col, rc, desiredWidth, currentWidth);
nsresult rv = GetCellWidth(row, col, rc, desiredWidth, currentWidth);
if (NS_FAILED(rv)) {
NS_NOTREACHED("invalid column");
continue;
}
rowWidth += desiredWidth;
col = col->GetNext();
}
if (rowWidth > mStringWidth)
@ -625,7 +627,9 @@ nsTreeBodyFrame::InvalidateColumn(nsITreeColumn* aCol)
if (!col)
return NS_ERROR_INVALID_ARG;
nsRect columnRect(col->GetX(), mInnerBox.y, col->GetWidth(), mInnerBox.height);
nsRect columnRect;
nsresult rv = col->GetRect(this, mInnerBox.y, mInnerBox.height, &columnRect);
NS_ENSURE_SUCCESS(rv, rv);
// When false then column is out of view
if (OffsetForHorzScroll(columnRect, PR_TRUE))
@ -670,8 +674,11 @@ nsTreeBodyFrame::InvalidateCell(PRInt32 aIndex, nsITreeColumn* aCol)
if (!col)
return NS_ERROR_INVALID_ARG;
nscoord yPos = mInnerBox.y+mRowHeight*aIndex;
nsRect cellRect(col->GetX(), yPos, col->GetWidth(), mRowHeight);
nsRect cellRect;
nsresult rv = col->GetRect(this, mInnerBox.y+mRowHeight*aIndex, mRowHeight,
&cellRect);
NS_ENSURE_SUCCESS(rv, rv);
if (OffsetForHorzScroll(cellRect, PR_TRUE))
nsIFrame::Invalidate(cellRect, PR_FALSE);
@ -726,7 +733,13 @@ nsTreeBodyFrame::InvalidateColumnRange(PRInt32 aStart, PRInt32 aEnd, nsITreeColu
if (aEnd > last)
aEnd = last;
nsRect rangeRect(col->GetX(), mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), col->GetWidth(), mRowHeight*(aEnd-aStart+1));
nsRect rangeRect;
nsresult rv = col->GetRect(this,
mInnerBox.y+mRowHeight*(aStart-mTopRowIndex),
mRowHeight*(aEnd-aStart+1),
&rangeRect);
NS_ENSURE_SUCCESS(rv, rv);
nsIFrame::Invalidate(rangeRect, PR_FALSE);
return NS_OK;
@ -1061,8 +1074,13 @@ nsTreeBodyFrame::GetCoordsForCellItem(PRInt32 aRow, nsITreeColumn* aCol, const n
for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol && currX < mInnerBox.x + mInnerBox.width;
currCol = currCol->GetNext()) {
// The Rect for the current cell.
nsRect cellRect(currX, mInnerBox.y + mRowHeight * (aRow - mTopRowIndex), currCol->GetWidth(), mRowHeight);
// The Rect for the current cell.
nscoord colWidth;
nsresult rv = currCol->GetWidthInTwips(this, &colWidth);
NS_ASSERTION(NS_SUCCEEDED(rv), "invalid column");
nsRect cellRect(currX, mInnerBox.y + mRowHeight * (aRow - mTopRowIndex),
colWidth, mRowHeight);
// Check the ID of the current column to see if it matches. If it doesn't
// increment the current X value and continue to the next column.
@ -1244,23 +1262,39 @@ nsTreeBodyFrame::AdjustForCellText(nsAutoString& aText,
nsIRenderingContext& aRenderingContext,
nsRect& aTextRect)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
nscoord width;
aRenderingContext.GetWidth(aText, width);
nscoord maxWidth = aTextRect.width;
if (aColumn->Overflow()) {
nsresult rv;
nsTreeColumn* nextColumn = aColumn->GetNext();
while (nextColumn && width > maxWidth) {
while (nextColumn && nextColumn->GetWidth() == 0)
while (nextColumn) {
nscoord width;
rv = nextColumn->GetWidthInTwips(this, &width);
NS_ASSERTION(NS_SUCCEEDED(rv), "nextColumn is invalid");
if (width != 0)
break;
nextColumn = nextColumn->GetNext();
}
if (nextColumn) {
nsAutoString nextText;
mView->GetCellText(aRowIndex, nextColumn, nextText);
if (nextText.Length() == 0) {
maxWidth += nextColumn->GetWidth();
nscoord width;
rv = nextColumn->GetWidthInTwips(this, &width);
NS_ASSERTION(NS_SUCCEEDED(rv), "nextColumn is invalid");
maxWidth += width;
nextColumn = nextColumn->GetNext();
}
else {
@ -1380,6 +1414,8 @@ nsTreeBodyFrame::GetItemWithinCellAt(nscoord aX, const nsRect& aCellRect,
PRInt32 aRowIndex,
nsTreeColumn* aColumn)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Obtain the properties for our cell.
PrefillPropertyArray(aRowIndex, aColumn);
mView->GetCellProperties(aRowIndex, aColumn, mScratchArray);
@ -1524,9 +1560,19 @@ nsTreeBodyFrame::GetCellAt(nscoord aX, nscoord aY, PRInt32* aRow,
// Determine the column hit.
for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol;
currCol = currCol->GetNext()) {
nsRect cellRect(currCol->GetX(), mInnerBox.y + mRowHeight * (*aRow - mTopRowIndex), currCol->GetWidth(), mRowHeight);
nsRect cellRect;
nsresult rv = currCol->GetRect(this,
mInnerBox.y +
mRowHeight * (*aRow - mTopRowIndex),
mRowHeight,
&cellRect);
if (NS_FAILED(rv)) {
NS_NOTREACHED("column has no frame");
continue;
}
if (!OffsetForHorzScroll(cellRect, PR_TRUE))
continue;
continue;
PRInt32 overflow = cellRect.x+cellRect.width-(mInnerBox.x+mInnerBox.width);
if (overflow > 0)
@ -1547,96 +1593,109 @@ nsTreeBodyFrame::GetCellAt(nscoord aX, nscoord aY, PRInt32* aRow,
}
}
void
nsresult
nsTreeBodyFrame::GetCellWidth(PRInt32 aRow, nsTreeColumn* aCol,
nsIRenderingContext* aRenderingContext,
nscoord& aDesiredSize, nscoord& aCurrentSize)
{
if (aCol) {
// The rect for the current cell.
nsRect cellRect(0, 0, aCol->GetWidth(), mRowHeight);
PRInt32 overflow = cellRect.x+cellRect.width-(mInnerBox.x+mInnerBox.width);
if (overflow > 0)
cellRect.width -= overflow;
NS_PRECONDITION(aCol, "aCol must not be null");
NS_PRECONDITION(aRenderingContext, "aRenderingContext must not be null");
// Adjust borders and padding for the cell.
nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
nsMargin bp(0,0,0,0);
GetBorderPadding(cellContext, bp);
// The rect for the current cell.
nscoord colWidth;
nsresult rv = aCol->GetWidthInTwips(this, &colWidth);
NS_ENSURE_SUCCESS(rv, rv);
aCurrentSize = cellRect.width;
aDesiredSize = bp.left + bp.right;
nsRect cellRect(0, 0, colWidth, mRowHeight);
if (aCol->IsPrimary()) {
// If the current Column is a Primary, then we need to take into account
// the indentation and possibly a twisty.
PRInt32 overflow = cellRect.x+cellRect.width-(mInnerBox.x+mInnerBox.width);
if (overflow > 0)
cellRect.width -= overflow;
// The amount of indentation is the indentation width (|mIndentation|) by the level.
PRInt32 level;
mView->GetLevel(aRow, &level);
aDesiredSize += mIndentation * level;
// Find the twisty rect by computing its size.
nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
// Adjust borders and padding for the cell.
nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
nsMargin bp(0,0,0,0);
GetBorderPadding(cellContext, bp);
nsRect imageSize;
nsRect twistyRect(cellRect);
GetTwistyRect(aRow, aCol, imageSize, twistyRect, GetPresContext(),
*aRenderingContext, twistyContext);
aCurrentSize = cellRect.width;
aDesiredSize = bp.left + bp.right;
// Add in the margins of the twisty element.
nsMargin twistyMargin;
twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
twistyRect.Inflate(twistyMargin);
if (aCol->IsPrimary()) {
// If the current Column is a Primary, then we need to take into account
// the indentation and possibly a twisty.
aDesiredSize += twistyRect.width;
}
nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
// Account for the width of the cell image.
nsRect imageSize = GetImageSize(aRow, aCol, PR_FALSE, imageContext);
// Add in the margins of the cell image.
nsMargin imageMargin;
imageContext->GetStyleMargin()->GetMargin(imageMargin);
imageSize.Inflate(imageMargin);
aDesiredSize += imageSize.width;
// The amount of indentation is the indentation width (|mIndentation|) by the level.
PRInt32 level;
mView->GetLevel(aRow, &level);
aDesiredSize += mIndentation * level;
// Get the cell text.
nsAutoString cellText;
mView->GetCellText(aRow, aCol, cellText);
// Find the twisty rect by computing its size.
nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
nsRect imageSize;
nsRect twistyRect(cellRect);
GetTwistyRect(aRow, aCol, imageSize, twistyRect, GetPresContext(),
*aRenderingContext, twistyContext);
// Get the borders and padding for the text.
GetBorderPadding(textContext, bp);
// Get the font style for the text and pass it to the rendering context.
aRenderingContext->SetFont(textContext->GetStyleFont()->mFont, nsnull);
// Add in the margins of the twisty element.
nsMargin twistyMargin;
twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
twistyRect.Inflate(twistyMargin);
// Get the width of the text itself
nscoord width;
aRenderingContext->GetWidth(cellText, width);
nscoord totalTextWidth = width + bp.left + bp.right;
aDesiredSize += totalTextWidth;
aDesiredSize += twistyRect.width;
}
nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
// Account for the width of the cell image.
nsRect imageSize = GetImageSize(aRow, aCol, PR_FALSE, imageContext);
// Add in the margins of the cell image.
nsMargin imageMargin;
imageContext->GetStyleMargin()->GetMargin(imageMargin);
imageSize.Inflate(imageMargin);
aDesiredSize += imageSize.width;
// Get the cell text.
nsAutoString cellText;
mView->GetCellText(aRow, aCol, cellText);
nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
// Get the borders and padding for the text.
GetBorderPadding(textContext, bp);
// Get the font style for the text and pass it to the rendering context.
aRenderingContext->SetFont(textContext->GetStyleFont()->mFont, nsnull);
// Get the width of the text itself
nscoord width;
aRenderingContext->GetWidth(cellText, width);
nscoord totalTextWidth = width + bp.left + bp.right;
aDesiredSize += totalTextWidth;
return NS_OK;
}
NS_IMETHODIMP
nsTreeBodyFrame::IsCellCropped(PRInt32 aRow, nsITreeColumn* aCol, PRBool *_retval)
{
nscoord currentSize, desiredSize;
nsCOMPtr<nsIRenderingContext> rc;
GetPresContext()->PresShell()->CreateRenderingContext(this, getter_AddRefs(rc));
nsresult rv;
nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
if (!col)
return NS_ERROR_INVALID_ARG;
GetCellWidth(aRow, col, rc, desiredSize, currentSize);
nsCOMPtr<nsIRenderingContext> rc;
rv = GetPresContext()->PresShell()->
CreateRenderingContext(this, getter_AddRefs(rc));
NS_ENSURE_SUCCESS(rv, rv);
rv = GetCellWidth(aRow, col, rc, desiredSize, currentSize);
NS_ENSURE_SUCCESS(rv, rv);
*_retval = desiredSize > currentSize;
return NS_OK;
}
@ -1784,6 +1843,7 @@ NS_IMETHODIMP nsTreeBodyFrame::EndUpdateBatch()
void
nsTreeBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, nsTreeColumn* aCol)
{
NS_PRECONDITION(!aCol || aCol->GetFrame(this), "invalid column passed");
mScratchArray->Clear();
// focus
@ -1895,13 +1955,13 @@ nsTreeBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, nsTreeColumn* aCol)
}
// Read special properties from attributes on the column content node
if (aCol->GetContent()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::insertbefore,
nsGkAtoms::_true, eCaseMatters))
if (aCol->mContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::insertbefore,
nsGkAtoms::_true, eCaseMatters))
mScratchArray->AppendElement(nsGkAtoms::insertbefore);
if (aCol->GetContent()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::insertafter,
nsGkAtoms::_true, eCaseMatters))
if (aCol->mContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::insertafter,
nsGkAtoms::_true, eCaseMatters))
mScratchArray->AppendElement(nsGkAtoms::insertafter);
}
}
@ -2638,15 +2698,17 @@ nsTreeBodyFrame::PaintTreeBody(nsIRenderingContext& aRenderingContext,
// is contained in the rows.
for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol;
currCol = currCol->GetNext()) {
nsRect colRect;
nsresult rv = currCol->GetRect(this, mInnerBox.y, mInnerBox.height,
&colRect);
// Don't paint hidden columns.
if (currCol->GetWidth()) {
nsRect colRect(currCol->GetX(), mInnerBox.y, currCol->GetWidth(), mInnerBox.height);
if (OffsetForHorzScroll(colRect, PR_FALSE)) {
nsRect dirtyRect;
colRect += aPt;
if (dirtyRect.IntersectRect(aDirtyRect, colRect)) {
PaintColumn(currCol, colRect, GetPresContext(), aRenderingContext, aDirtyRect);
}
if (NS_FAILED(rv) || colRect.width == 0) continue;
if (OffsetForHorzScroll(colRect, PR_FALSE)) {
nsRect dirtyRect;
colRect += aPt;
if (dirtyRect.IntersectRect(aDirtyRect, colRect)) {
PaintColumn(currCol, colRect, GetPresContext(), aRenderingContext, aDirtyRect);
}
}
}
@ -2685,6 +2747,8 @@ nsTreeBodyFrame::PaintColumn(nsTreeColumn* aColumn,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Now obtain the properties for our cell.
PrefillPropertyArray(-1, aColumn);
mView->GetColumnProperties(aColumn, mScratchArray);
@ -2718,6 +2782,8 @@ nsTreeBodyFrame::PaintRow(PRInt32 aRowIndex,
if (!mView)
return;
nsresult rv;
// Now obtain the properties for our row.
// XXX Automatically fill in the following props: open, closed, container, leaf, selected, focused
PrefillPropertyArray(aRowIndex, nsnull);
@ -2771,7 +2837,13 @@ nsTreeBodyFrame::PaintRow(PRInt32 aRowIndex,
nsTreeColumn* primaryCol = mColumns->GetPrimaryColumn();
if (primaryCol) {
// Paint the primary cell.
nsRect cellRect(primaryCol->GetX(), rowRect.y, primaryCol->GetWidth(), rowRect.height);
nsRect cellRect;
rv = primaryCol->GetRect(this, rowRect.y, rowRect.height, &cellRect);
if (NS_FAILED(rv)) {
NS_NOTREACHED("primary column is invalid");
return;
}
if (OffsetForHorzScroll(cellRect, PR_FALSE)) {
cellRect.x += aPt.x;
nsRect dirtyRect;
@ -2783,11 +2855,18 @@ nsTreeBodyFrame::PaintRow(PRInt32 aRowIndex,
// Paint the left side of the separator.
nscoord currX;
nsTreeColumn* previousCol = primaryCol->GetPrevious();
if (previousCol)
currX = (previousCol->GetX() - mHorzPosition) + previousCol->GetWidth()
+ aPt.x;
else
if (previousCol) {
nsRect prevColRect;
rv = previousCol->GetRect(this, 0, 0, &prevColRect);
if (NS_SUCCEEDED(rv)) {
currX = (prevColRect.x - mHorzPosition) + prevColRect.width + aPt.x;
} else {
NS_NOTREACHED("The column before the primary column is invalid");
currX = rowRect.x;
}
} else {
currX = rowRect.x;
}
PRInt32 level;
mView->GetLevel(aRowIndex, &level);
@ -2813,18 +2892,20 @@ nsTreeBodyFrame::PaintRow(PRInt32 aRowIndex,
// Now loop over our cells. Only paint a cell if it intersects with our dirty rect.
for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol;
currCol = currCol->GetNext()) {
nsRect cellRect;
rv = currCol->GetRect(this, rowRect.y, rowRect.height, &cellRect);
// Don't paint cells in hidden columns.
if (currCol->GetWidth()) {
nsRect cellRect(currCol->GetX(), rowRect.y, currCol->GetWidth(), rowRect.height);
if (OffsetForHorzScroll(cellRect, PR_FALSE)) {
cellRect.x += aPt.x;
nsRect dirtyRect;
nscoord dummy;
if (dirtyRect.IntersectRect(aDirtyRect, cellRect))
PaintCell(aRowIndex, currCol, cellRect, aPresContext,
aRenderingContext, aDirtyRect, dummy, aPt);
}
if (NS_FAILED(rv) || cellRect.width == 0)
continue;
if (OffsetForHorzScroll(cellRect, PR_FALSE)) {
cellRect.x += aPt.x;
nsRect dirtyRect;
nscoord dummy;
if (dirtyRect.IntersectRect(aDirtyRect, cellRect))
PaintCell(aRowIndex, currCol, cellRect, aPresContext,
aRenderingContext, aDirtyRect, dummy, aPt);
}
}
}
@ -2892,6 +2973,8 @@ nsTreeBodyFrame::PaintCell(PRInt32 aRowIndex,
nscoord& aCurrX,
nsPoint aPt)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Now obtain the properties for our cell.
// XXX Automatically fill in the following props: open, closed, container, leaf, selected, focused, and the col ID.
PrefillPropertyArray(aRowIndex, aColumn);
@ -3057,6 +3140,8 @@ nsTreeBodyFrame::PaintTwisty(PRInt32 aRowIndex,
nscoord& aRemainingWidth,
nscoord& aCurrX)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Paint the twisty, but only if we are a non-empty container.
PRBool shouldPaint = PR_FALSE;
PRBool isContainer = PR_FALSE;
@ -3139,6 +3224,8 @@ nsTreeBodyFrame::PaintImage(PRInt32 aRowIndex,
nscoord& aRemainingWidth,
nscoord& aCurrX)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Resolve style for the image.
nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
@ -3268,6 +3355,8 @@ nsTreeBodyFrame::PaintText(PRInt32 aRowIndex,
const nsRect& aDirtyRect,
nscoord& aCurrX)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Now obtain the text for our cell.
nsAutoString text;
mView->GetCellText(aRowIndex, aColumn, text);
@ -3374,6 +3463,8 @@ nsTreeBodyFrame::PaintCheckbox(PRInt32 aRowIndex,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Resolve style for the checkbox.
nsStyleContext* checkboxContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecheckbox);
@ -3428,6 +3519,7 @@ nsTreeBodyFrame::PaintProgressMeter(PRInt32 aRowIndex,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
// Resolve style for the progress meter. It contains all the info we need
// to lay ourselves out and to paint.
@ -3499,10 +3591,15 @@ nsTreeBodyFrame::PaintDropFeedback(const nsRect& aDropFeedbackRect,
// Adjust for the primary cell.
nsTreeColumn* primaryCol = mColumns->GetPrimaryColumn();
if (primaryCol)
currX = primaryCol->GetX() - mHorzPosition;
else
if (primaryCol) {
nsresult rv = primaryCol->GetXInTwips(this, &currX);
NS_ASSERTION(NS_SUCCEEDED(rv), "primary column is invalid?");
currX -= mHorzPosition;
} else {
currX = aDropFeedbackRect.x;
}
PrefillPropertyArray(mSlots->mDropRow, primaryCol);
@ -3643,9 +3740,15 @@ NS_IMETHODIMP nsTreeBodyFrame::EnsureCellIsVisible(PRInt32 aRow, nsITreeColumn*
ScrollParts parts = GetScrollParts();
nscoord result = -1;
nsresult rv;
nscoord columnPos = col->GetX();
nscoord columnWidth = col->GetWidth();
nscoord columnPos;
rv = col->GetXInTwips(this, &columnPos);
if(NS_FAILED(rv)) return rv;
nscoord columnWidth;
rv = col->GetWidthInTwips(this, &columnWidth);
if(NS_FAILED(rv)) return rv;
// If the start of the column is before the
// start of the horizontal view, then scroll
@ -3657,7 +3760,7 @@ NS_IMETHODIMP nsTreeBodyFrame::EnsureCellIsVisible(PRInt32 aRow, nsITreeColumn*
result = ((columnPos + columnWidth) - (mHorzPosition + mInnerBox.width)) + mHorzPosition;
if (result != -1) {
nsresult rv = ScrollHorzInternal(parts, result);
rv = ScrollHorzInternal(parts, result);
if(NS_FAILED(rv)) return rv;
}
@ -3684,7 +3787,13 @@ nsresult nsTreeBodyFrame::ScrollToColumnInternal(const ScrollParts& aParts,
nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
if (!col)
return NS_ERROR_INVALID_ARG;
return ScrollHorzInternal(aParts, col->GetX());
nscoord x;
nsresult rv = col->GetXInTwips(this, &x);
if (NS_FAILED(rv))
return rv;
return ScrollHorzInternal(aParts, x);
}
NS_IMETHODIMP nsTreeBodyFrame::ScrollToHorizontalPosition(PRInt32 aHorizontalPosition)

Просмотреть файл

@ -117,10 +117,21 @@ public:
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
friend nsIFrame* NS_NewTreeBodyFrame(nsIPresShell* aPresShell);
struct ScrollParts {
nsIScrollbarFrame* mVScrollbar;
nsIContent* mVScrollbarContent;
nsIScrollbarFrame* mHScrollbar;
nsIContent* mHScrollbarContent;
nsIScrollableView* mColumnsScrollableView;
};
void PaintTreeBody(nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect, nsPoint aPt);
protected:
// This method paints a specific column background of the tree.
void PaintColumn(nsTreeColumn* aColumn,
const nsRect& aColumnRect,
@ -212,17 +223,7 @@ public:
const nsRect& aRect,
const nsRect& aDirtyRect);
friend nsIFrame* NS_NewTreeBodyFrame(nsIPresShell* aPresShell);
struct ScrollParts {
nsIScrollbarFrame* mVScrollbar;
nsIContent* mVScrollbarContent;
nsIScrollbarFrame* mHScrollbar;
nsIContent* mHScrollbarContent;
nsIScrollableView* mColumnsScrollableView;
};
protected:
PRInt32 GetLastVisibleRow() {
return mTopRowIndex + mPageLength;
};
@ -326,9 +327,9 @@ protected:
// Get the base element, <tree> or <select>
nsIContent* GetBaseElement();
void GetCellWidth(PRInt32 aRow, nsTreeColumn* aCol,
nsIRenderingContext* aRenderingContext,
nscoord& aDesiredSize, nscoord& aCurrentSize);
nsresult GetCellWidth(PRInt32 aRow, nsTreeColumn* aCol,
nsIRenderingContext* aRenderingContext,
nscoord& aDesiredSize, nscoord& aCurrentSize);
nscoord CalcMaxRowWidth();
// Translate the given rect horizontally from tree coordinates into the

Просмотреть файл

@ -52,13 +52,18 @@
static NS_DEFINE_CID(kTreeColumnImplCID, NS_TREECOLUMN_IMPL_CID);
// Column class that caches all the info about our column.
nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIFrame* aFrame)
: mFrame(aFrame),
nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent)
: mContent(aContent),
mColumns(aColumns),
mNext(nsnull),
mPrevious(nsnull)
{
CacheAttributes();
NS_ASSERTION(aContent &&
aContent->NodeInfo()->Equals(nsGkAtoms::treecol,
kNameSpaceID_XUL),
"nsTreeColumn's content must be a <xul:treecol>");
Invalidate();
}
nsTreeColumn::~nsTreeColumn()
@ -82,10 +87,76 @@ NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsTreeColumn)
NS_IMPL_RELEASE(nsTreeColumn)
nsIFrame*
nsTreeColumn::GetFrame(nsIFrame* aBodyFrame)
{
NS_PRECONDITION(aBodyFrame, "null frame?");
nsIPresShell *shell = aBodyFrame->GetPresContext()->PresShell();
if (!shell)
return nsnull;
return shell->GetPrimaryFrameFor(mContent);
}
nsIFrame*
nsTreeColumn::GetFrame()
{
nsCOMPtr<nsIDocument> document = mContent->GetDocument();
if (!document)
return nsnull;
nsIPresShell *shell = document->GetShellAt(0);
if (!shell)
return nsnull;
return shell->GetPrimaryFrameFor(mContent);
}
nsresult
nsTreeColumn::GetRect(nsIFrame* aBodyFrame, nscoord aY, nscoord aHeight, nsRect* aResult)
{
nsIFrame* frame = GetFrame(aBodyFrame);
if (!frame) {
*aResult = nsRect();
return NS_ERROR_FAILURE;
}
*aResult = frame->GetRect();
aResult->y = aY;
aResult->height = aHeight;
return NS_OK;
}
nsresult
nsTreeColumn::GetXInTwips(nsIFrame* aBodyFrame, nscoord* aResult)
{
nsIFrame* frame = GetFrame(aBodyFrame);
if (!frame) {
*aResult = 0;
return NS_ERROR_FAILURE;
}
*aResult = frame->GetRect().x;
return NS_OK;
};
nsresult
nsTreeColumn::GetWidthInTwips(nsIFrame* aBodyFrame, nscoord* aResult)
{
nsIFrame* frame = GetFrame(aBodyFrame);
if (!frame) {
*aResult = 0;
return NS_ERROR_FAILURE;
}
*aResult = frame->GetRect().width;
return NS_OK;
};
NS_IMETHODIMP
nsTreeColumn::GetElement(nsIDOMElement** aElement)
{
return CallQueryInterface(GetContent(), aElement);
return CallQueryInterface(mContent, aElement);
}
NS_IMETHODIMP
@ -98,16 +169,22 @@ nsTreeColumn::GetColumns(nsITreeColumns** aColumns)
NS_IMETHODIMP
nsTreeColumn::GetX(PRInt32* aX)
{
float t2p = mFrame->GetPresContext()->TwipsToPixels();
*aX = NSToIntRound(GetX() * t2p);
nsIFrame* frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
float t2p = frame->GetPresContext()->TwipsToPixels();
*aX = NSToIntRound(frame->GetRect().x * t2p);
return NS_OK;
}
NS_IMETHODIMP
nsTreeColumn::GetWidth(PRInt32* aWidth)
{
float t2p = mFrame->GetPresContext()->TwipsToPixels();
*aWidth = NSToIntRound(GetWidth() * t2p);
nsIFrame* frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
float t2p = frame->GetPresContext()->TwipsToPixels();
*aWidth = NSToIntRound(frame->GetRect().width * t2p);
return NS_OK;
}
@ -191,17 +268,11 @@ nsTreeColumn::GetPrevious(nsITreeColumn** _retval)
NS_IMETHODIMP
nsTreeColumn::Invalidate()
{
CacheAttributes();
return NS_OK;
}
void
nsTreeColumn::CacheAttributes()
{
nsIContent* content = GetContent();
nsIFrame* frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
// Fetch the Id.
content->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
// If we have an Id, cache the Id as an atom.
if (!mId.IsEmpty()) {
@ -209,12 +280,12 @@ nsTreeColumn::CacheAttributes()
}
// Cache our index.
nsTreeUtils::GetColumnIndex(content, &mIndex);
nsTreeUtils::GetColumnIndex(mContent, &mIndex);
const nsStyleVisibility* vis = mFrame->GetStyleVisibility();
const nsStyleVisibility* vis = frame->GetStyleVisibility();
// Cache our text alignment policy.
const nsStyleText* textStyle = mFrame->GetStyleText();
const nsStyleText* textStyle = frame->GetStyleText();
mTextAlignment = textStyle->mTextAlign;
if (mTextAlignment == 0 || mTextAlignment == 2) { // Left or Right
@ -224,29 +295,29 @@ nsTreeColumn::CacheAttributes()
// Figure out if we're the primary column (that has to have indentation
// and twisties drawn.
mIsPrimary = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
nsGkAtoms::_true, eCaseMatters);
mIsPrimary = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
nsGkAtoms::_true, eCaseMatters);
// Figure out if we're a cycling column (one that doesn't cause a selection
// to happen).
mIsCycler = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
nsGkAtoms::_true, eCaseMatters);
mIsEditable = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
mIsCycler = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
nsGkAtoms::_true, eCaseMatters);
mIsSelectable = !content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
nsGkAtoms::_false, eCaseMatters);
mIsEditable = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
nsGkAtoms::_true, eCaseMatters);
mOverflow = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
nsGkAtoms::_true, eCaseMatters);
mIsSelectable = !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
nsGkAtoms::_false, eCaseMatters);
mOverflow = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
nsGkAtoms::_true, eCaseMatters);
// Figure out our column type. Default type is text.
mType = nsITreeColumn::TYPE_TEXT;
static nsIContent::AttrValuesArray typestrings[] =
{&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, nsnull};
switch (content->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
typestrings, eCaseMatters)) {
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
typestrings, eCaseMatters)) {
case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break;
}
@ -255,8 +326,8 @@ nsTreeColumn::CacheAttributes()
mCropStyle = 0;
static nsIContent::AttrValuesArray cropstrings[] =
{&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nsnull};
switch (content->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
cropstrings, eCaseMatters)) {
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
cropstrings, eCaseMatters)) {
case 0:
mCropStyle = 1;
break;
@ -265,6 +336,8 @@ nsTreeColumn::CacheAttributes()
mCropStyle = 2;
break;
}
return NS_OK;
}
@ -353,7 +426,7 @@ nsTreeColumns::GetSortedColumn(nsITreeColumn** _retval)
EnsureColumns();
*_retval = nsnull;
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
if (nsContentUtils::HasNonEmptyAttr(currCol->GetContent(), kNameSpaceID_None,
if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
nsGkAtoms::sortDirection)) {
NS_ADDREF(*_retval = currCol);
return NS_OK;
@ -374,11 +447,9 @@ nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval)
first = primary = sorted = nsnull;
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
nsIContent* content = currCol->GetContent();
// Skip hidden columns.
if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
nsGkAtoms::_true, eCaseMatters))
if (currCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
nsGkAtoms::_true, eCaseMatters))
continue;
// Skip non-text column
@ -388,7 +459,7 @@ nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval)
if (!first)
first = currCol;
if (nsContentUtils::HasNonEmptyAttr(content, kNameSpaceID_None,
if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
nsGkAtoms::sortDirection)) {
// Use sorted column as the key.
sorted = currCol;
@ -418,7 +489,7 @@ nsTreeColumns::GetColumnFor(nsIDOMElement* aElement, nsITreeColumn** _retval)
*_retval = nsnull;
nsCOMPtr<nsIContent> element = do_QueryInterface(aElement);
for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
if (currCol->GetContent() == element) {
if (currCol->mContent == element) {
NS_ADDREF(*_retval = currCol);
break;
}
@ -550,7 +621,7 @@ nsTreeColumns::EnsureColumns()
if (colContent->NodeInfo()->Equals(nsGkAtoms::treecol,
kNameSpaceID_XUL)) {
// Create a new column structure.
nsTreeColumn* col = new nsTreeColumn(this, colFrame);
nsTreeColumn* col = new nsTreeColumn(this, colContent);
if (!col)
return;

Просмотреть файл

@ -51,7 +51,7 @@ class nsTreeColumns;
// information about each column.
class nsTreeColumn : public nsITreeColumn {
public:
nsTreeColumn(nsTreeColumns* aColumns, nsIFrame* aFrame);
nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent);
~nsTreeColumn();
NS_DECL_ISUPPORTS
@ -61,15 +61,21 @@ public:
friend class nsTreeColumns;
protected:
void CacheAttributes();
nsIFrame* GetFrame();
nsIFrame* GetFrame(nsIFrame* aBodyFrame);
nsIContent* GetContent() { return mFrame->GetContent(); };
/**
* Returns a rect with x and width taken from the frame's rect and specified
* y and height. May fail in case there's no frame for the column.
*/
nsresult GetRect(nsIFrame* aBodyFrame, nscoord aY, nscoord aHeight,
nsRect* aResult);
nsresult GetXInTwips(nsIFrame* aBodyFrame, nscoord* aResult);
nsresult GetWidthInTwips(nsIFrame* aBodyFrame, nscoord* aResult);
void SetColumns(nsTreeColumns* aColumns) { mColumns = aColumns; };
PRInt32 GetX() { return mFrame->GetRect().x; };
nscoord GetWidth() { return mFrame->GetRect().width; };
const nsAString& GetId() { return mId; };
nsIAtom* GetAtom() { return mAtom; };
@ -92,7 +98,10 @@ protected:
void SetPrevious(nsTreeColumn* aPrevious) { mPrevious = aPrevious; };
private:
nsIFrame* mFrame;
/**
* Non-null nsIContent for the associated <treecol> element.
*/
nsCOMPtr<nsIContent> mContent;
nsTreeColumns* mColumns;
@ -145,6 +154,14 @@ protected:
private:
nsITreeBoxObject* mTree;
/**
* The first column in the list of columns. All of the columns are supposed
* to be "alive", i.e. have a frame. This is achieved by clearing the columns
* list each time an nsTreeColFrame is destroyed.
*
* XXX this means that new nsTreeColumn objects are unnecessarily created
* for untouched columns.
*/
nsTreeColumn* mFirstColumn;
};