Files
tubestation/layout/generic/nsLineBox.cpp
troy@netscape.com 3932716d1d Now line boxes are allocated out of the pres shell arena. This reduces the
overhead of memory allocation, and it gets us recycling which speeds up
resize reflows
2000-03-12 03:00:51 +00:00

912 lines
21 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.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
*/
#include "nsLineBox.h"
#include "nsISpaceManager.h"
#include "nsIStyleContext.h"
#include "nsLineLayout.h"
#include "prprf.h"
#ifdef DEBUG
#include "nsISizeOfHandler.h"
#include "nsLayoutAtoms.h"
#endif
#ifdef DEBUG
static PRInt32 ctorCount;
PRInt32 nsLineBox::GetCtorCount() { return ctorCount; }
#endif
MOZ_DECL_CTOR_COUNTER(nsLineBox);
nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock)
: mFirstChild(aFrame),
mNext(nsnull),
mBounds(0, 0, 0, 0),
mMaxElementWidth(0),
mData(nsnull),
mMaximumWidth(-1)
{
MOZ_COUNT_CTOR(nsLineBox);
#ifdef DEBUG
++ctorCount;
#endif
mAllFlags = 0;
#if NS_STYLE_CLEAR_NONE > 0
mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
#endif
SetChildCount(aCount);
MarkDirty();
mFlags.mBlock = aIsBlock;
}
nsLineBox::~nsLineBox()
{
MOZ_COUNT_DTOR(nsLineBox);
Cleanup();
}
nsLineBox*
NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
PRInt32 aCount, PRBool aIsBlock)
{
return new (aPresShell)nsLineBox(aFrame, aCount, aIsBlock);
}
// Overloaded new operator. Uses an arena (which comes from the presShell)
// to perform the allocation.
void*
nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell)
{
void* result = nsnull;
aPresShell->AllocateFrame(sz, &result);
return result;
}
// Overloaded delete operator. Doesn't actually free the memory, because we
// use an arena
void
nsLineBox::operator delete(void* aPtr, size_t sz)
{
}
void
nsLineBox::Destroy(nsIPresShell* aPresShell)
{
// Destroy the object. This won't actually free the memory, though
delete this;
// Have the pres shell recycle the memory
aPresShell->FreeFrame(sizeof(*this), (void*)this);
}
void
nsLineBox::Cleanup()
{
if (mData) {
if (IsBlock()) {
delete mBlockData;
}
else {
delete mInlineData;
}
mData = nsnull;
}
}
#ifdef DEBUG
static void
ListFloaters(FILE* out, PRInt32 aIndent, const nsFloaterCacheList& aFloaters)
{
nsAutoString frameName;
nsFloaterCache* fc = aFloaters.Head();
while (fc) {
nsFrame::IndentBy(out, aIndent);
nsPlaceholderFrame* ph = fc->mPlaceholder;
if (nsnull != ph) {
fprintf(out, "placeholder@%p ", ph);
nsIFrame* frame = ph->GetOutOfFlowFrame();
if (nsnull != frame) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(frame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
frameDebug->GetFrameName(frameName);
fputs(frameName, out);
}
}
fprintf(out, " %s region={%d,%d,%d,%d} combinedArea={%d,%d,%d,%d}",
fc->mIsCurrentLineFloater ? "cl" : "bcl",
fc->mRegion.x, fc->mRegion.y,
fc->mRegion.width, fc->mRegion.height,
fc->mCombinedArea.x, fc->mCombinedArea.y,
fc->mCombinedArea.width, fc->mCombinedArea.height);
fprintf(out, "\n");
}
fc = fc->Next();
}
}
#endif
char*
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
{
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s[0x%x]",
IsBlock() ? "block" : "inline",
IsDirty() ? "dirty" : "",
IsImpactedByFloater() ? "impacted" : "",
IsTrimmed() ? "trimmed" : "",
mAllFlags);
return aBuf;
}
#ifdef DEBUG
void
nsLineBox::List(nsIPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
{
PRInt32 i;
for (i = aIndent; --i >= 0; ) fputs(" ", out);
char cbuf[100];
fprintf(out, "line %p: count=%d state=%s ",
this, GetChildCount(), StateToString(cbuf, sizeof(cbuf)));
if (0 != GetCarriedOutBottomMargin()) {
fprintf(out, "bm=%d ", GetCarriedOutBottomMargin());
}
if (0 != mMaxElementWidth) {
fprintf(out, "mew=%d ", mMaxElementWidth);
}
fprintf(out, "{%d,%d,%d,%d} ",
mBounds.x, mBounds.y, mBounds.width, mBounds.height);
if (mData) {
fprintf(out, "ca={%d,%d,%d,%d} ",
mData->mCombinedArea.x, mData->mCombinedArea.y,
mData->mCombinedArea.width, mData->mCombinedArea.height);
}
fprintf(out, "<\n");
nsIFrame* frame = mFirstChild;
PRInt32 n = GetChildCount();
while (--n >= 0) {
nsIFrameDebug* frameDebug;
if (NS_SUCCEEDED(frame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
frameDebug->List(aPresContext, out, aIndent + 1);
}
frame->GetNextSibling(&frame);
}
for (i = aIndent; --i >= 0; ) fputs(" ", out);
if (HasFloaters()) {
fputs("> floaters <\n", out);
ListFloaters(out, aIndent + 1, mInlineData->mFloaters);
for (i = aIndent; --i >= 0; ) fputs(" ", out);
}
fputs(">\n", out);
}
#endif
nsIFrame*
nsLineBox::LastChild() const
{
nsIFrame* frame = mFirstChild;
PRInt32 n = GetChildCount() - 1;
while (--n >= 0) {
frame->GetNextSibling(&frame);
}
return frame;
}
PRBool
nsLineBox::IsLastChild(nsIFrame* aFrame) const
{
nsIFrame* lastFrame = LastChild();
return aFrame == lastFrame;
}
PRInt32
nsLineBox::IndexOf(nsIFrame* aFrame) const
{
PRInt32 i, n = GetChildCount();
nsIFrame* frame = mFirstChild;
for (i = 0; i < n; i++) {
if (frame == aFrame) {
return i;
}
frame->GetNextSibling(&frame);
}
return -1;
}
void
nsLineBox::DeleteLineList(nsIPresContext* aPresContext, nsLineBox* aLine)
{
if (nsnull != aLine) {
// Delete our child frames before doing anything else. In particular
// we do all of this before our base class releases it's hold on the
// view.
for (nsIFrame* child = aLine->mFirstChild; child; ) {
nsIFrame* nextChild;
child->GetNextSibling(&nextChild);
child->Destroy(aPresContext);
child = nextChild;
}
while (nsnull != aLine) {
nsLineBox* next = aLine->mNext;
delete aLine;
aLine = next;
}
}
}
nsLineBox*
nsLineBox::LastLine(nsLineBox* aLine)
{
if (nsnull != aLine) {
while (nsnull != aLine->mNext) {
aLine = aLine->mNext;
}
}
return aLine;
}
nsLineBox*
nsLineBox::FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame,
PRInt32* aFrameIndexInLine)
{
NS_PRECONDITION(aFrameIndexInLine && aLine && aFrame, "null ptr");
while (nsnull != aLine) {
PRInt32 ix = aLine->IndexOf(aFrame);
if (ix >= 0) {
*aFrameIndexInLine = ix;
return aLine;
}
aLine = aLine->mNext;
}
*aFrameIndexInLine = -1;
return nsnull;
}
nscoord
nsLineBox::GetCarriedOutBottomMargin() const
{
return (IsBlock() && mBlockData) ? mBlockData->mCarriedOutBottomMargin : 0;
}
void
nsLineBox::SetCarriedOutBottomMargin(nscoord aValue)
{
if (IsBlock()) {
if (aValue) {
if (!mBlockData) {
mBlockData = new ExtraBlockData(mBounds);
}
if (mBlockData) {
mBlockData->mCarriedOutBottomMargin = aValue;
}
}
else if (mBlockData) {
mBlockData->mCarriedOutBottomMargin = aValue;
MaybeFreeData();
}
}
}
void
nsLineBox::MaybeFreeData()
{
if (mData && (mData->mCombinedArea == mBounds)) {
if (IsInline()) {
if (mInlineData->mFloaters.IsEmpty()) {
delete mInlineData;
mInlineData = nsnull;
}
}
else if (0 == mBlockData->mCarriedOutBottomMargin) {
delete mBlockData;
mBlockData = nsnull;
}
}
}
// XXX get rid of this???
nsFloaterCache*
nsLineBox::GetFirstFloater()
{
NS_ABORT_IF_FALSE(IsInline(), "block line can't have floaters");
return mInlineData ? mInlineData->mFloaters.Head() : nsnull;
}
// XXX this might be too eager to free memory
void
nsLineBox::FreeFloaters(nsFloaterCacheFreeList& aFreeList)
{
NS_ABORT_IF_FALSE(IsInline(), "block line can't have floaters");
if (IsInline()) {
if (mInlineData) {
aFreeList.Append(mInlineData->mFloaters);
MaybeFreeData();
}
}
}
void
nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager)
{
if (IsInline()) {
if (mInlineData) {
nsFloaterCache* floaterCache = mInlineData->mFloaters.Head();
while (floaterCache) {
nsIFrame* floater = floaterCache->mPlaceholder->GetOutOfFlowFrame();
aSpaceManager->RemoveRegion(floater);
floaterCache = floaterCache->Next();
}
}
}
}
void
nsLineBox::AppendFloaters(nsFloaterCacheFreeList& aFreeList)
{
NS_ABORT_IF_FALSE(IsInline(), "block line can't have floaters");
if (IsInline()) {
if (aFreeList.NotEmpty()) {
if (!mInlineData) {
mInlineData = new ExtraInlineData(mBounds);
}
if (mInlineData) {
mInlineData->mFloaters.Append(aFreeList);
}
}
}
}
PRBool
nsLineBox::RemoveFloater(nsIFrame* aFrame)
{
NS_ABORT_IF_FALSE(IsInline(), "block line can't have floaters");
if (IsInline() && mInlineData) {
nsFloaterCache* fc = mInlineData->mFloaters.Find(aFrame);
if (fc) {
// Note: the placeholder is part of the line's child list
// and will be removed later.
fc->mPlaceholder->SetOutOfFlowFrame(nsnull);
mInlineData->mFloaters.Remove(fc);
MaybeFreeData();
return PR_TRUE;
}
}
return PR_FALSE;
}
void
nsLineBox::SetCombinedArea(const nsRect& aCombinedArea)
{
NS_ASSERTION(aCombinedArea.width >= 0, "illegal width for combined area");
NS_ASSERTION(aCombinedArea.height >= 0, "illegal height for combined area");
if (aCombinedArea != mBounds) {
if (mData) {
mData->mCombinedArea = aCombinedArea;
}
else {
if (IsInline()) {
mInlineData = new ExtraInlineData(aCombinedArea);
}
else {
mBlockData = new ExtraBlockData(aCombinedArea);
}
}
}
else {
if (mData) {
// Store away new value so that MaybeFreeData compares against
// the right value.
mData->mCombinedArea = aCombinedArea;
}
MaybeFreeData();
}
}
void
nsLineBox::GetCombinedArea(nsRect* aResult)
{
if (aResult) {
*aResult = mData ? mData->mCombinedArea : mBounds;
}
}
#ifdef DEBUG
PRInt32
nsLineBox::ListLength(nsLineBox* aLine)
{
PRInt32 count = 0;
while (aLine) {
count++;
aLine = aLine->mNext;
}
return count;
}
nsIAtom*
nsLineBox::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
{
NS_PRECONDITION(aResult, "null OUT parameter pointer");
*aResult = sizeof(*this);
nsIAtom* atom;
if (IsBlock()) {
atom = nsLayoutAtoms::lineBoxBlockSmall;
if (mBlockData) {
atom = nsLayoutAtoms::lineBoxBlockBig;
*aResult += sizeof(*mBlockData);
}
}
else {
atom = nsLayoutAtoms::lineBoxSmall;
if (mInlineData) {
atom = nsLayoutAtoms::lineBoxBig;
*aResult += sizeof(*mInlineData);
// Add in the size needed for floaters associated with this line
if (HasFloaters()) {
PRUint32 floatersSize;
mInlineData->mFloaters.SizeOf(aHandler, &floatersSize);
// Base size of embedded object was included in sizeof(*this) above
floatersSize -= sizeof(mInlineData->mFloaters);
aHandler->AddSize(nsLayoutAtoms::lineBoxFloaters, floatersSize);
}
}
}
return atom;
}
#endif
//----------------------------------------------------------------------
static NS_DEFINE_IID(kILineIteratorIID, NS_ILINE_ITERATOR_IID);
static nsLineBox* gDummyLines[1];
nsLineIterator::nsLineIterator()
{
NS_INIT_REFCNT();
mLines = gDummyLines;
mNumLines = 0;
mIndex = 0;
mRightToLeft = PR_FALSE;
}
nsLineIterator::~nsLineIterator()
{
if (mLines != gDummyLines) {
delete [] mLines;
}
}
NS_IMPL_ISUPPORTS(nsLineIterator, kILineIteratorIID)
nsresult
nsLineIterator::Init(nsLineBox* aLines, PRBool aRightToLeft)
{
mRightToLeft = aRightToLeft;
// Count the lines
PRInt32 numLines = 0;
nsLineBox* line = aLines;
while (line) {
numLines++;
line = line->mNext;
}
if (0 == numLines) {
// Use gDummyLines so that we don't need null pointer checks in
// the accessor methods
mLines = gDummyLines;
return NS_OK;
}
// Make a linear array of the lines
mLines = new nsLineBox*[numLines];
if (!mLines) {
// Use gDummyLines so that we don't need null pointer checks in
// the accessor methods
mLines = gDummyLines;
return NS_ERROR_OUT_OF_MEMORY;
}
nsLineBox** lp = mLines;
line = aLines;
while (line) {
*lp++ = line;
line = line->mNext;
}
mNumLines = numLines;
return NS_OK;
}
NS_IMETHODIMP
nsLineIterator::GetNumLines(PRInt32* aResult)
{
NS_PRECONDITION(aResult, "null OUT ptr");
if (!aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mNumLines;
return NS_OK;
}
NS_IMETHODIMP
nsLineIterator::GetDirection(PRBool* aIsRightToLeft)
{
NS_PRECONDITION(aIsRightToLeft, "null OUT ptr");
if (!aIsRightToLeft) {
return NS_ERROR_NULL_POINTER;
}
*aIsRightToLeft = mRightToLeft;
return NS_OK;
}
NS_IMETHODIMP
nsLineIterator::GetLine(PRInt32 aLineNumber,
nsIFrame** aFirstFrameOnLine,
PRInt32* aNumFramesOnLine,
nsRect& aLineBounds,
PRUint32* aLineFlags)
{
NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
NS_ENSURE_ARG_POINTER(aLineFlags);
if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
*aFirstFrameOnLine = nsnull;
*aNumFramesOnLine = 0;
aLineBounds.SetRect(0, 0, 0, 0);
return NS_OK;
}
nsLineBox* line = mLines[aLineNumber];
*aFirstFrameOnLine = line->mFirstChild;
*aNumFramesOnLine = line->GetChildCount();
aLineBounds = line->mBounds;
PRUint32 flags = 0;
if (line->IsBlock()) {
flags |= NS_LINE_FLAG_IS_BLOCK;
}
else {
if (line->IsTrimmed())
flags |= NS_LINE_FLAG_IS_TRIMMED;
if (line->HasBreak())
flags |= NS_LINE_FLAG_ENDS_IN_BREAK;
}
*aLineFlags = flags;
return NS_OK;
}
NS_IMETHODIMP
nsLineIterator::FindLineContaining(nsIFrame* aFrame,
PRInt32* aLineNumberResult)
{
nsLineBox* line = mLines[0];
PRInt32 lineNumber = 0;
while (line) {
if (line->Contains(aFrame)) {
*aLineNumberResult = lineNumber;
return NS_OK;
}
line = line->mNext;
lineNumber++;
}
*aLineNumberResult = -1;
return NS_OK;
}
NS_IMETHODIMP
nsLineIterator::FindLineAt(nscoord aY,
PRInt32* aLineNumberResult)
{
nsLineBox* line = mLines[0];
if (!line || (aY < line->mBounds.y)) {
*aLineNumberResult = -1;
return NS_OK;
}
PRInt32 lineNumber = 0;
while (line) {
if ((aY >= line->mBounds.y) && (aY < line->mBounds.YMost())) {
*aLineNumberResult = lineNumber;
return NS_OK;
}
line = line->mNext;
lineNumber++;
}
*aLineNumberResult = mNumLines;
return NS_OK;
}
NS_IMETHODIMP
nsLineIterator::FindFrameAt(PRInt32 aLineNumber,
nscoord aX,
nsIFrame** aFrameFound,
PRBool* aXIsBeforeFirstFrame,
PRBool* aXIsAfterLastFrame)
{
NS_PRECONDITION(aFrameFound && aXIsBeforeFirstFrame && aXIsAfterLastFrame,
"null OUT ptr");
if (!aFrameFound || !aXIsBeforeFirstFrame || !aXIsAfterLastFrame) {
return NS_ERROR_NULL_POINTER;
}
if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
return NS_ERROR_INVALID_ARG;
}
nsLineBox* line = mLines[aLineNumber];
if (!line) {
*aFrameFound = nsnull;
*aXIsBeforeFirstFrame = PR_TRUE;
*aXIsAfterLastFrame = PR_FALSE;
return NS_OK;
}
if (aX < line->mBounds.x) {
nsIFrame* frame;
if (mRightToLeft) {
frame = line->LastChild();
}
else {
frame = line->mFirstChild;
}
*aFrameFound = frame;
*aXIsBeforeFirstFrame = PR_TRUE;
*aXIsAfterLastFrame = PR_FALSE;
return NS_OK;
}
else if (aX >= line->mBounds.XMost()) {
nsIFrame* frame;
if (mRightToLeft) {
frame = line->mFirstChild;
}
else {
frame = line->LastChild();
}
*aFrameFound = frame;
*aXIsBeforeFirstFrame = PR_FALSE;
*aXIsAfterLastFrame = PR_TRUE;
return NS_OK;
}
// Find the frame closest to the X coordinate. Gaps can occur
// between frames (because of margins) so we split the gap in two
// when checking.
*aXIsBeforeFirstFrame = PR_FALSE;
*aXIsAfterLastFrame = PR_FALSE;
nsRect r1, r2;
nsIFrame* frame = line->mFirstChild;
PRInt32 n = line->GetChildCount();
if (mRightToLeft) {
while (--n >= 0) {
nsIFrame* nextFrame;
frame->GetNextSibling(&nextFrame);
frame->GetRect(r1);
if (aX > r1.x) {
break;
}
if (nextFrame) {
nextFrame->GetRect(r2);
if (aX > r2.XMost()) {
nscoord rightEdge = r2.XMost();
nscoord delta = r1.x - rightEdge;
if (aX < rightEdge + delta/2) {
frame = nextFrame;
}
break;
}
}
else {
*aXIsBeforeFirstFrame = PR_TRUE;
}
frame = nextFrame;
}
}
else {
while (--n >= 0) {
nsIFrame* nextFrame;
frame->GetNextSibling(&nextFrame);
frame->GetRect(r1);
if (aX < r1.XMost()) {
break;
}
if (nextFrame) {
nextFrame->GetRect(r2);
if (aX < r2.x) {
nscoord rightEdge = r1.XMost();
nscoord delta = r2.x - rightEdge;
if (aX >= rightEdge + delta/2) {
frame = nextFrame;
}
break;
}
}
else {
*aXIsAfterLastFrame = PR_TRUE;
}
frame = nextFrame;
}
}
*aFrameFound = frame;
return NS_OK;
}
//----------------------------------------------------------------------
nsFloaterCacheList::~nsFloaterCacheList()
{
nsFloaterCache* floater = mHead;
while (floater) {
nsFloaterCache* next = floater->mNext;
delete floater;
floater = next;
}
mHead = nsnull;
}
nsFloaterCache*
nsFloaterCacheList::Tail() const
{
nsFloaterCache* fc = mHead;
while (fc) {
if (!fc->mNext) {
break;
}
fc = fc->mNext;
}
return fc;
}
void
nsFloaterCacheList::Append(nsFloaterCacheFreeList& aList)
{
nsFloaterCache* tail = Tail();
if (tail) {
tail->mNext = aList.mHead;
}
else {
mHead = aList.mHead;
}
aList.mHead = nsnull;
aList.mTail = nsnull;
}
nsFloaterCache*
nsFloaterCacheList::Find(nsIFrame* aOutOfFlowFrame)
{
nsFloaterCache* fc = mHead;
while (fc) {
if (fc->mPlaceholder->GetOutOfFlowFrame() == aOutOfFlowFrame) {
break;
}
fc = fc->Next();
}
return fc;
}
void
nsFloaterCacheList::Remove(nsFloaterCache* aElement)
{
nsFloaterCache** fcp = &mHead;
nsFloaterCache* fc;
while (nsnull != (fc = *fcp)) {
if (fc == aElement) {
*fcp = fc->mNext;
break;
}
fcp = &fc->mNext;
}
}
#ifdef DEBUG
void
nsFloaterCacheList::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
{
NS_PRECONDITION(aResult, "null OUT parameter pointer");
*aResult = sizeof(*this);
// Add in the space for each floater
for (nsFloaterCache* cache = Head(); cache; cache = cache->Next()) {
*aResult += sizeof(*cache);
}
}
#endif
//----------------------------------------------------------------------
void
nsFloaterCacheFreeList::Append(nsFloaterCacheList& aList)
{
if (mTail) {
mTail->mNext = aList.mHead;
}
else {
mHead = aList.mHead;
}
mTail = aList.Tail();
aList.mHead = nsnull;
}
nsFloaterCache*
nsFloaterCacheFreeList::Alloc()
{
nsFloaterCache* fc = mHead;
if (mHead) {
if (mHead == mTail) {
mHead = mTail = nsnull;
}
else {
mHead = fc->mNext;
}
fc->mNext = nsnull;
}
else {
fc = new nsFloaterCache();
}
return fc;
}
void
nsFloaterCacheFreeList::Append(nsFloaterCache* aFloater)
{
aFloater->mNext = nsnull;
if (mTail) {
mTail->mNext = aFloater;
mTail = aFloater;
}
else {
mHead = mTail = aFloater;
}
}
//----------------------------------------------------------------------
MOZ_DECL_CTOR_COUNTER(nsFloaterCache);
nsFloaterCache::nsFloaterCache()
: mPlaceholder(nsnull),
mIsCurrentLineFloater(PR_TRUE),
mMargins(0, 0, 0, 0),
mOffsets(0, 0, 0, 0),
mCombinedArea(0, 0, 0, 0),
mNext(nsnull)
{
MOZ_COUNT_CTOR(nsFloaterCache);
}
#ifdef DEBUG
nsFloaterCache::~nsFloaterCache()
{
MOZ_COUNT_DTOR(nsFloaterCache);
}
#endif