better table reflow debugging including support for elapsed time. sr=buster.

git-svn-id: svn://10.0.0.236/trunk@85493 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
karnaze%netscape.com 2001-01-25 15:55:51 +00:00
parent ba0227a44d
commit d95bd4f152
27 changed files with 973 additions and 195 deletions

View File

@ -213,6 +213,11 @@ struct nsHTMLReflowState {
// is from the top of the frame tree.
PRInt32 mReflowDepth;
#ifdef DEBUG
// hook for attaching debug info (e.g. tables may attach a timer during reflow)
void* mDebugHook;
#endif
// Note: The copy constructor is written by the compiler
// automatically. You can use that and then override specific values
// if you want, or you can call Init as desired...

View File

@ -174,6 +174,7 @@ nsHTMLReflowState::Init(nsIPresContext* aPresContext,
mCompactMarginWidth = 0;
mAlignCharOffset = 0;
mUseAlignCharOffset = 0;
mDebugHook = nsnull;
frame->GetStyleData(eStyleStruct_Position,
(const nsStyleStruct*&)mStylePosition);

View File

@ -213,6 +213,11 @@ struct nsHTMLReflowState {
// is from the top of the frame tree.
PRInt32 mReflowDepth;
#ifdef DEBUG
// hook for attaching debug info (e.g. tables may attach a timer during reflow)
void* mDebugHook;
#endif
// Note: The copy constructor is written by the compiler
// automatically. You can use that and then override specific values
// if you want, or you can call Init as desired...

View File

@ -174,6 +174,7 @@ nsHTMLReflowState::Init(nsIPresContext* aPresContext,
mCompactMarginWidth = 0;
mAlignCharOffset = 0;
mUseAlignCharOffset = 0;
mDebugHook = nsnull;
frame->GetStyleData(eStyleStruct_Position,
(const nsStyleStruct*&)mStylePosition);

View File

@ -24,7 +24,7 @@ DEPTH=..\..\..\..
LIBRARY_NAME=raptorhtmltable_s
MODULE=raptor
DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN
DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN
CPPSRCS= nsCellMap.cpp \
nsTableCellFrame.cpp \

View File

@ -57,11 +57,18 @@ nsTableCellFrame::nsTableCellFrame()
mColIndex = 0;
mPriorAvailWidth = 0;
mBorderEdges = nsnull;
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
mBlockTimer = new nsReflowTimer(this);
#endif
}
nsTableCellFrame::~nsTableCellFrame()
{
delete mBorderEdges;
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
NS_IMETHODIMP
@ -688,7 +695,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame", aReflowState.reason);
if (nsDebugTable::gRflCell) nsTableFrame::DebugReflow("TC::Rfl", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
nsresult rv = NS_OK;
// this should probably be cached somewhere
@ -797,13 +806,17 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
firstKid->GetOrigin(kidOrigin);
}
if (nsDebugTable::gRflArea) nsTableFrame::DebugReflow("Area::Rfl en", firstKid, &kidReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState);
#endif
ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
kidOrigin.x, kidOrigin.y, 0, aStatus);
if (isStyleChanged) {
Invalidate(aPresContext, mRect);
}
if (nsDebugTable::gRflArea) nsTableFrame::DebugReflow("Area::Rfl ex", firstKid, nsnull, &kidSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState, &kidSize, aStatus);
#endif
#ifdef NS_DEBUG
DebugCheckChildSize(firstKid, kidSize, availSize, (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth));
@ -917,7 +930,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// remember my desired size for this reflow
SetDesiredSize(aDesiredSize);
if (nsDebugTable::gRflCell) nsTableFrame::DebugReflow("TC::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return NS_OK;
}

View File

@ -285,6 +285,10 @@ public:
nsBorderEdges *mBorderEdges; // one list of border segments for each side of the table frame
// used only for the collapsing border model
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsReflowTimer* mTimer;
nsReflowTimer* mBlockTimer;
#endif
};
inline nsresult nsTableCellFrame::GetRowIndex(PRInt32 &aRowIndex) const

View File

@ -29,6 +29,7 @@
class nsTableColFrame;
class nsTableFrame;
enum nsTableColGroupType {
eColGroupContent = 0, // there is real col group content associated
eColGroupAnonymousCol = 1, // the result of a col
@ -217,7 +218,6 @@ protected:
unsigned int mType:4;
unsigned int mUnused:28;
} mBits;
};
inline nsTableColGroupFrame::nsTableColGroupFrame()

View File

@ -68,22 +68,6 @@ static void GetPlaceholderFor(nsIPresContext& aPresContext, nsIFrame& aFrame, ns
static const PRInt32 kColumnWidthIncrement=10;
#if 1
PRBool nsDebugTable::gRflTableOuter = PR_FALSE;
PRBool nsDebugTable::gRflTable = PR_FALSE;
PRBool nsDebugTable::gRflRowGrp = PR_FALSE;
PRBool nsDebugTable::gRflRow = PR_FALSE;
PRBool nsDebugTable::gRflCell = PR_FALSE;
PRBool nsDebugTable::gRflArea = PR_FALSE;
#else
PRBool nsDebugTable::gRflTableOuter = PR_TRUE;
PRBool nsDebugTable::gRflTable = PR_TRUE;
PRBool nsDebugTable::gRflRowGrp = PR_TRUE;
PRBool nsDebugTable::gRflRow = PR_TRUE;
PRBool nsDebugTable::gRflCell = PR_TRUE;
PRBool nsDebugTable::gRflArea = PR_TRUE;
#endif
static PRInt32 gRflCount = 0;
/* ----------- InnerTableReflowState ---------- */
@ -184,6 +168,9 @@ nsTableFrame::nsTableFrame()
nsCRT::memset (mColumnWidths, 0, mColumnWidthsLength*sizeof(PRInt32));
}
#endif
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
NS_IMPL_ADDREF_INHERITED(nsTableFrame, nsHTMLContainerFrame)
@ -259,6 +246,9 @@ nsTableFrame::~nsTableFrame()
delete mTableLayoutStrategy;
mTableLayoutStrategy = nsnull;
}
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
NS_IMETHODIMP
@ -1640,8 +1630,10 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason);
if (nsDebugTable::gRflTable) nsTableFrame::DebugReflow("T::Rfl en", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
// Initialize out parameter
if (nsnull != aDesiredSize.maxElementSize) {
aDesiredSize.maxElementSize->width = 0;
@ -1804,7 +1796,9 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
}
if (nsDebugTable::gRflTable) nsTableFrame::DebugReflow("T::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return rv;
}
@ -4615,32 +4609,10 @@ PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
}
#define INDENT_PER_LEVEL 2
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
void nsTableFrame::DebugGetIndent(const nsIFrame* aFrame,
char* aBuf)
{
PRInt32 numLevels = 0;
nsIFrame* parent = nsnull;
aFrame->GetParent(&parent);
while (parent) {
nsIAtom* frameType = nsnull;
parent->GetFrameType(&frameType);
if ((nsDebugTable::gRflTableOuter && (nsLayoutAtoms::tableOuterFrame == frameType)) ||
(nsDebugTable::gRflTable && (nsLayoutAtoms::tableFrame == frameType)) ||
(nsDebugTable::gRflRowGrp && (nsLayoutAtoms::tableRowGroupFrame == frameType)) ||
(nsDebugTable::gRflRow && (nsLayoutAtoms::tableRowFrame == frameType)) ||
(nsDebugTable::gRflCell && (nsLayoutAtoms::tableCellFrame == frameType)) ||
(nsDebugTable::gRflArea && (nsLayoutAtoms::areaFrame == frameType))) {
numLevels++;
}
NS_IF_RELEASE(frameType);
parent->GetParent(&parent);
}
PRInt32 indent = INDENT_PER_LEVEL * numLevels;
nsCRT::memset (aBuf, ' ', indent);
aBuf[indent] = 0;
}
static PRInt32 gRflCount = 0;
#define INDENT_PER_LEVEL 1
void PrettyUC(nscoord aSize,
char* aBuf)
@ -4653,43 +4625,88 @@ void PrettyUC(nscoord aSize,
}
}
void nsTableFrame::DebugReflow(char* aMessage,
const nsIFrame* aFrame,
const nsHTMLReflowState* aState,
const nsHTMLReflowMetrics* aMetrics,
const nsReflowStatus aStatus)
void GetFrameTypeName(nsIAtom* aFrameType,
char* aName)
{
if (nsLayoutAtoms::tableOuterFrame == aFrameType)
strcpy(aName, "Tbl");
else if (nsLayoutAtoms::tableFrame == aFrameType)
strcpy(aName, "Tbl");
else if (nsLayoutAtoms::tableRowGroupFrame == aFrameType)
strcpy(aName, "RowG");
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
strcpy(aName, "Row");
else if (nsLayoutAtoms::tableCellFrame == aFrameType)
strcpy(aName, "Cell");
else if (nsLayoutAtoms::blockFrame == aFrameType)
strcpy(aName, "Block");
else
NS_ASSERTION(PR_FALSE, "invalid call to GetFrameTypeName");
}
#ifdef DEBUG_TABLE_REFLOW
void DebugGetIndent(const nsIFrame* aFrame,
char* aBuf)
{
PRInt32 numLevels = 0;
nsIFrame* parent = nsnull;
aFrame->GetParent(&parent);
while (parent) {
nsCOMPtr<nsIAtom> frameType;
parent->GetFrameType(getter_AddRefs(frameType));
if ((nsLayoutAtoms::tableOuterFrame == frameType.get()) ||
(nsLayoutAtoms::tableFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowGroupFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowFrame == frameType.get()) ||
(nsLayoutAtoms::tableCellFrame == frameType.get())) {
numLevels++;
}
parent->GetParent(&parent);
}
PRInt32 indent = INDENT_PER_LEVEL * numLevels;
nsCRT::memset (aBuf, ' ', indent);
aBuf[indent] = 0;
}
void nsTableFrame::DebugReflow(nsIFrame* aFrame,
nsHTMLReflowState& aState,
nsHTMLReflowMetrics* aMetrics,
nsReflowStatus aStatus)
{
// get the frame type
nsCOMPtr<nsIAtom> fType;
aFrame->GetFrameType(getter_AddRefs(fType));
char fName[128];
GetFrameTypeName(fType.get(), fName);
char indent[256];
nsTableFrame::DebugGetIndent(aFrame, indent);
printf("%s%s %p ", indent, aMessage, aFrame);
char width[32];
char height[32];
if (aState) {
PrettyUC(aState->availableWidth, width);
PrettyUC(aState->availableHeight, height);
printf("rea=%d av=(%s,%s) ", aState->reason, width, height);
PrettyUC(aState->mComputedWidth, width);
PrettyUC(aState->mComputedHeight, height);
printf("comp=(%s,%s) count=%d \n ", width, height, gRflCount);
DebugGetIndent(aFrame, indent);
printf("%s%s %p ", indent, fName, aFrame);
char width[16];
char height[16];
if (!aMetrics) { // start
PrettyUC(aState.availableWidth, width);
printf("r=%d a=%s ", aState.reason, width);
PrettyUC(aState.mComputedWidth, width);
PrettyUC(aState.mComputedHeight, height);
printf("c=%s,%s cnt=%d \n", width, height, gRflCount);
gRflCount++;
//if (32 == gRflCount) {
// NS_ASSERTION(PR_FALSE, "stop");
//}
}
if (aMetrics) {
if (aState) {
printf("%s", indent);
}
if (aMetrics) { // stop
PrettyUC(aMetrics->width, width);
PrettyUC(aMetrics->height, height);
printf("des=(%s,%s) ", width, height);
printf("d=%s,%s ", width, height);
if (aMetrics->maxElementSize) {
PrettyUC(aMetrics->maxElementSize->width, width);
PrettyUC(aMetrics->maxElementSize->height, height);
printf("maxElem=(%s,%s)", width, height);
printf("me=%s ", width);
}
if (aMetrics->mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
printf("max=%d ", aMetrics->mMaximumWidth);
PrettyUC(aMetrics->mMaximumWidth, width);
printf("m=%s ", width);
}
if (NS_FRAME_COMPLETE != aStatus) {
printf("status=%d", aStatus);
@ -4698,6 +4715,206 @@ void nsTableFrame::DebugReflow(char* aMessage,
}
}
#else
nsReflowTimer* GetFrameTimer(nsIFrame* aFrame,
nsIAtom* aFrameType)
{
if (nsLayoutAtoms::tableOuterFrame == aFrameType)
return ((nsTableOuterFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableFrame == aFrameType)
return ((nsTableFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableRowGroupFrame == aFrameType)
return ((nsTableRowGroupFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
return ((nsTableRowFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableCellFrame == aFrameType)
return ((nsTableCellFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::blockFrame == aFrameType) {
nsIFrame* parentFrame;
aFrame->GetParent(&parentFrame);
nsCOMPtr<nsIAtom> fType;
parentFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableCellFrame == fType) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)parentFrame;
// fix up the block timer, which may be referring to the cell
if (cellFrame->mBlockTimer->mFrame == parentFrame) {
cellFrame->mBlockTimer->mFrame = aFrame;
NS_IF_RELEASE(cellFrame->mBlockTimer->mFrameType);
cellFrame->mBlockTimer->mFrameType = nsLayoutAtoms::blockFrame;
NS_ADDREF(cellFrame->mBlockTimer->mFrameType);
}
return cellFrame->mBlockTimer;
}
}
return nsnull;
}
void DebugReflowPrint(nsReflowTimer& aTimer,
PRUint32 aLevel,
PRBool aSummary)
{
// set up the indentation
char indentChar[128];
PRInt32 indent = INDENT_PER_LEVEL * aLevel;
nsCRT::memset (indentChar, ' ', indent);
indentChar[indent] = 0;
// get the frame type
char fName[128];
GetFrameTypeName(aTimer.mFrameType, fName);
// print the timer
printf("\n%s%s %dms %p", indentChar, fName, aTimer.Elapsed(), aTimer.mFrame);
if (aSummary) {
printf(" times=%d", aTimer.mNumStarts);
}
else {
char avWidth[16];
char compWidth[16];
char compHeight[16];
char desWidth[16];
char desHeight[16];
PrettyUC(aTimer.mAvailWidth, avWidth);
PrettyUC(aTimer.mComputedWidth, compWidth);
PrettyUC(aTimer.mComputedHeight, compHeight);
PrettyUC(aTimer.mDesiredWidth, desWidth);
PrettyUC(aTimer.mDesiredHeight, desHeight);
printf(" r=%d a=%s c=%s,%s d=%s,%s", aTimer.mReason, avWidth, compWidth,
compHeight, desWidth, desHeight);
if (aTimer.mMaxElementWidth >= 0) {
PrettyUC(aTimer.mMaxElementWidth, avWidth);
printf(" me=%s", avWidth);
}
if (aTimer.mMaxWidth >= 0) {
PrettyUC(aTimer.mMaxWidth, avWidth);
printf(" m=%s", avWidth);
}
if (NS_FRAME_COMPLETE != aTimer.mStatus) {
printf(" status=%d", aTimer.mStatus);
}
printf(" cnt=%d", aTimer.mCount);
}
// print the timer's children
nsVoidArray& children = aTimer.mChildren;
PRInt32 numChildren = children.Count();
for (PRInt32 childX = 0; childX < numChildren; childX++) {
nsReflowTimer* child = (nsReflowTimer*)children.ElementAt(childX);
if (child) {
DebugReflowPrint(*child, aLevel + 1, aSummary);
}
else NS_ASSERTION(PR_FALSE, "bad DebugTimeReflow");
}
}
void nsTableFrame::DebugReflow(nsIFrame* aFrame,
nsHTMLReflowState& aState,
nsHTMLReflowMetrics* aMetrics,
nsReflowStatus aStatus)
{
// get the parent timer
const nsHTMLReflowState* parentRS = aState.parentReflowState;
nsReflowTimer* parentTimer = nsnull;
while (parentRS) {
parentTimer = (nsReflowTimer *)parentRS->mDebugHook;
if (parentTimer) break;
parentRS = parentRS->parentReflowState;
}
// get the the frame summary timer
nsCOMPtr<nsIAtom> frameType = nsnull;
aFrame->GetFrameType(getter_AddRefs(frameType));
nsReflowTimer* frameTimer = GetFrameTimer(aFrame, frameType.get());
if (!frameTimer) {
NS_ASSERTION(PR_FALSE, "no frame timer");
return;
}
if (!aMetrics) { // start
// create the reflow timer
nsReflowTimer* timer = new nsReflowTimer(aFrame);
if (!timer) {
NS_ASSERTION(PR_FALSE, "could not create timer");
return;
}
timer->mReason = aState.reason;
timer->mAvailWidth = aState.availableWidth;
timer->mComputedWidth = aState.mComputedWidth;
timer->mComputedHeight = aState.mComputedHeight;
timer->mCount = gRflCount++;
timer->Start();
aState.mDebugHook = timer;
if (parentTimer) {
parentTimer->mChildren.AppendElement(timer);
}
// start the frame summary timer
frameTimer->Start();
}
else {
// stop the reflow timer
nsReflowTimer* timer = (nsReflowTimer *)aState.mDebugHook;
if (timer) {
timer->Stop();
timer->mDesiredWidth = aMetrics->width;
timer->mDesiredHeight = aMetrics->height;
timer->mMaxElementWidth = (aMetrics->maxElementSize)
? aMetrics->maxElementSize->width : -1;
timer->mMaxWidth = (aMetrics->mFlags & NS_REFLOW_CALC_MAX_WIDTH)
? aMetrics->mMaximumWidth : -1;
timer->mStatus = aStatus;
}
else {
NS_ASSERTION(PR_FALSE, "bad DebugTimeReflow");
return;
}
if (!parentTimer) {
// print out all of the reflow timers
DebugReflowPrint(*timer, 0, PR_FALSE);
timer->Destroy();
}
// stop the frame summary timer
frameTimer->Stop();
}
}
void nsTableFrame::DebugReflowDone(nsIFrame* aFrame)
{
// get the timer of aFrame
nsCOMPtr<nsIAtom> frameType = nsnull;
aFrame->GetFrameType(getter_AddRefs(frameType));
nsReflowTimer* thisTimer = GetFrameTimer(aFrame, frameType.get());
// get the nearest ancestor frame with a timer
nsReflowTimer* ancestorTimer;
nsIFrame* ancestorFrame;
aFrame->GetParent(&ancestorFrame);
while (ancestorFrame) {
nsCOMPtr<nsIAtom> frameType = nsnull;
ancestorFrame->GetFrameType(getter_AddRefs(frameType));
ancestorTimer = GetFrameTimer(ancestorFrame, frameType.get());
if (ancestorTimer) break;
ancestorFrame->GetParent(&ancestorFrame);
}
if (ancestorTimer) { // add this timer to its parent
ancestorTimer->mChildren.AppendElement(thisTimer);
nsCOMPtr<nsIAtom> fType;
aFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableCellFrame == fType) {
// add the cell block timer as a child of the cell timer
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aFrame;
cellFrame->mTimer->mChildren.AppendElement(cellFrame->mBlockTimer);
}
}
else { // print out all of the frame timers
printf("\n\nSUMMARY OF REFLOW BY FRAME\n");
DebugReflowPrint(*thisTimer, 0, PR_TRUE);
thisTimer->Destroy();
}
}
#endif
#endif
PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex)
{
PRBool result = PR_FALSE;

View File

@ -46,6 +46,87 @@ struct InnerTableReflowState;
struct nsStylePosition;
struct nsStyleSpacing;
#ifdef DEBUG_TABLE_REFLOW_TIMING
#ifdef WIN32
#include <windows.h>
#endif
class nsReflowTimer
{
public:
nsReflowTimer(nsIFrame* aFrame) {
mFrame = aFrame;
aFrame->GetFrameType(&mFrameType);
Reset();
}
void Destroy() {
PRInt32 numChildren = mChildren.Count();
for (PRInt32 childX = 0; childX < numChildren; childX++) {
((nsReflowTimer*)mChildren.ElementAt(childX))->Destroy();
}
NS_IF_RELEASE(mFrameType);
delete this;
}
void Print(PRUint32 aIndent,
char* aHeader = 0) {
if (aHeader) {
printf("%s", aHeader);
}
printf(" elapsed=%d numStarts=%d \n", Elapsed(), mNumStarts);
}
PRUint32 Elapsed() {
return mTotalTime;
}
void Reset() {
mTotalTime = mNumStarts = 0;
mStarted = PR_FALSE;
}
void Start() {
NS_ASSERTION(!mStarted, "started timer without stopping");
#ifdef WIN32
mStartTime = GetTickCount();
#else
mStartTime = 0;
#endif
mStarted = PR_TRUE;
mNumStarts++;
}
void Stop() {
NS_ASSERTION(mStarted, "stopped timer without starting");
mTotalTime += GetTickCount() - mStartTime;
mStarted = PR_FALSE;
}
PRUint32 mTotalTime;
PRUint32 mStartTime;
PRUint32 mNumStarts;
PRBool mStarted;
const nsIFrame* mFrame;
nsIAtom* mFrameType; // needed for frame summary timer
nsReflowReason mReason;
nsVoidArray mChildren;
PRInt32 mCount;
// reflow state/reflow metrics data
nscoord mAvailWidth;
nscoord mComputedWidth;
nscoord mComputedHeight;
nscoord mMaxElementWidth;
nscoord mMaxWidth; // preferred width
nscoord mDesiredWidth;
nscoord mDesiredHeight;
nsReflowStatus mStatus;
private:
~nsReflowTimer() {}
};
#endif
/**
* Child list name indices
* @see #GetAdditionalChildListName()
@ -53,15 +134,6 @@ struct nsStyleSpacing;
#define NS_TABLE_FRAME_COLGROUP_LIST_INDEX 0
#define NS_TABLE_FRAME_LAST_LIST_INDEX NS_TABLE_FRAME_COLGROUP_LIST_INDEX
struct nsDebugTable
{
static PRBool gRflTableOuter;
static PRBool gRflTable;
static PRBool gRflRowGrp;
static PRBool gRflRow;
static PRBool gRflCell;
static PRBool gRflArea;
};
/* ============================================================================ */
/** nsTableFrame maps the inner portion of a table (everything except captions.)
@ -416,15 +488,6 @@ public:
PRBool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(PRBool aValue);
static void DebugReflow(char* aMessage,
const nsIFrame* aFrame,
const nsHTMLReflowState* aState,
const nsHTMLReflowMetrics* aMetrics,
const nsReflowStatus aStatus = NS_FRAME_COMPLETE);
static void DebugGetIndent(const nsIFrame* aFrame,
char* aBuf);
protected:
/** protected constructor.
@ -873,6 +936,19 @@ protected:
// used only for the collapsing border model
nscoord mPercentBasisForRows;
nscoord mPreferredWidth;
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
public:
static void DebugReflow(nsIFrame* aFrame,
nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics* aMetrics = nsnull,
nsReflowStatus aStatus = NS_FRAME_COMPLETE);
#ifdef DEBUG_TABLE_REFLOW_TIMING
static void DebugReflowDone(nsIFrame* aFrame);
nsReflowTimer* mTimer;
#endif
#endif
};

View File

@ -95,10 +95,16 @@ NS_IMPL_RELEASE_INHERITED(nsTableOuterFrame, nsHTMLContainerFrame)
nsTableOuterFrame::nsTableOuterFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
nsTableOuterFrame::~nsTableOuterFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
nsresult nsTableOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
@ -1390,7 +1396,9 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame", aOuterRS.reason);
if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl en", this, &aOuterRS, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS);
#endif
nsresult rv = NS_OK;
PRUint8 captionSide = GetCaptionSide();
@ -1499,7 +1507,9 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext,
}
}
if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS, &aDesiredSize, aStatus);
#endif
return rv;
}

View File

@ -27,6 +27,10 @@
#include "nsBlockFrame.h"
#include "nsITableLayout.h"
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
#endif
struct nsStyleTable;
class nsTableCaptionFrame : public nsBlockFrame
@ -354,6 +358,11 @@ private:
nsSize mMaxElementSize;
nscoord mInnerTableMaximumWidth;
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
#endif
};
inline nscoord nsTableOuterFrame::GetMinCaptionWidth()

View File

@ -115,6 +115,16 @@ nsTableRowFrame::nsTableRowFrame()
mBits.mMinRowSpan = 1;
mBits.mRowIndex = 0;
ResetTallestCell(0);
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
nsTableRowFrame::~nsTableRowFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
NS_IMETHODIMP
@ -1488,7 +1498,9 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame", aReflowState.reason);
if (nsDebugTable::gRflRow) nsTableFrame::DebugReflow("TR::Rfl en", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
nsresult rv = NS_OK;
// Initialize 'out' parameters (aStatus set below, undefined if rv returns an error)
@ -1548,7 +1560,9 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
mMaxElementSize = *aDesiredSize.maxElementSize;
}
if (nsDebugTable::gRflRow) nsTableFrame::DebugReflow("TR::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return rv;
}

View File

@ -28,6 +28,10 @@
class nsTableFrame;
class nsTableCellFrame;
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
#endif
/* ----------- RowReflowState ---------- */
struct RowReflowState {
@ -71,6 +75,8 @@ struct RowReflowState {
class nsTableRowFrame : public nsHTMLContainerFrame
{
public:
virtual ~nsTableRowFrame();
NS_IMETHOD Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
@ -321,6 +327,11 @@ private:
// max-ascent and max-descent amongst all cells that have 'vertical-align: baseline'
nscoord mMaxCellAscent; // does include cells with rowspan > 1
nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
#endif
};
inline PRInt32 nsTableRowFrame::GetRowIndex() const

View File

@ -42,6 +42,20 @@
#include "nsCellMap.h"//table cell navigation
nsTableRowGroupFrame::nsTableRowGroupFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
nsTableRowGroupFrame::~nsTableRowGroupFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
/* ----------- nsTableRowGroupFrame ---------- */
nsrefcnt nsTableRowGroupFrame::AddRef(void)
{
@ -1055,7 +1069,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame", aReflowState.reason);
if (nsDebugTable::gRflRowGrp) nsTableFrame::DebugReflow("TRG::Rfl", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
nsresult rv=NS_OK;
// Initialize out parameter
@ -1163,7 +1179,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
mMaxElementSize = *aDesiredSize.maxElementSize;
}
if (nsDebugTable::gRflRowGrp) nsTableFrame::DebugReflow("TRG::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return rv;
}

View File

@ -29,6 +29,9 @@
class nsTableFrame;
class nsTableRowFrame;
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
#endif
/* ----------- RowGroupReflowState ---------- */
@ -103,6 +106,7 @@ public:
*/
friend nsresult
NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
virtual ~nsTableRowGroupFrame();
NS_IMETHOD AppendFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
@ -223,6 +227,7 @@ public:
protected:
nsTableRowGroupFrame();
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@ -341,6 +346,10 @@ public:
private:
nsSize mMaxElementSize;
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
#endif
};
inline void nsTableRowGroupFrame::GetMaxElementSize(nsSize& aMaxElementSize) const

View File

@ -57,11 +57,18 @@ nsTableCellFrame::nsTableCellFrame()
mColIndex = 0;
mPriorAvailWidth = 0;
mBorderEdges = nsnull;
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
mBlockTimer = new nsReflowTimer(this);
#endif
}
nsTableCellFrame::~nsTableCellFrame()
{
delete mBorderEdges;
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
NS_IMETHODIMP
@ -688,7 +695,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame", aReflowState.reason);
if (nsDebugTable::gRflCell) nsTableFrame::DebugReflow("TC::Rfl", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
nsresult rv = NS_OK;
// this should probably be cached somewhere
@ -797,13 +806,17 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
firstKid->GetOrigin(kidOrigin);
}
if (nsDebugTable::gRflArea) nsTableFrame::DebugReflow("Area::Rfl en", firstKid, &kidReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState);
#endif
ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
kidOrigin.x, kidOrigin.y, 0, aStatus);
if (isStyleChanged) {
Invalidate(aPresContext, mRect);
}
if (nsDebugTable::gRflArea) nsTableFrame::DebugReflow("Area::Rfl ex", firstKid, nsnull, &kidSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState, &kidSize, aStatus);
#endif
#ifdef NS_DEBUG
DebugCheckChildSize(firstKid, kidSize, availSize, (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth));
@ -917,7 +930,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// remember my desired size for this reflow
SetDesiredSize(aDesiredSize);
if (nsDebugTable::gRflCell) nsTableFrame::DebugReflow("TC::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return NS_OK;
}

View File

@ -285,6 +285,10 @@ public:
nsBorderEdges *mBorderEdges; // one list of border segments for each side of the table frame
// used only for the collapsing border model
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsReflowTimer* mTimer;
nsReflowTimer* mBlockTimer;
#endif
};
inline nsresult nsTableCellFrame::GetRowIndex(PRInt32 &aRowIndex) const

View File

@ -29,6 +29,7 @@
class nsTableColFrame;
class nsTableFrame;
enum nsTableColGroupType {
eColGroupContent = 0, // there is real col group content associated
eColGroupAnonymousCol = 1, // the result of a col
@ -217,7 +218,6 @@ protected:
unsigned int mType:4;
unsigned int mUnused:28;
} mBits;
};
inline nsTableColGroupFrame::nsTableColGroupFrame()

View File

@ -68,22 +68,6 @@ static void GetPlaceholderFor(nsIPresContext& aPresContext, nsIFrame& aFrame, ns
static const PRInt32 kColumnWidthIncrement=10;
#if 1
PRBool nsDebugTable::gRflTableOuter = PR_FALSE;
PRBool nsDebugTable::gRflTable = PR_FALSE;
PRBool nsDebugTable::gRflRowGrp = PR_FALSE;
PRBool nsDebugTable::gRflRow = PR_FALSE;
PRBool nsDebugTable::gRflCell = PR_FALSE;
PRBool nsDebugTable::gRflArea = PR_FALSE;
#else
PRBool nsDebugTable::gRflTableOuter = PR_TRUE;
PRBool nsDebugTable::gRflTable = PR_TRUE;
PRBool nsDebugTable::gRflRowGrp = PR_TRUE;
PRBool nsDebugTable::gRflRow = PR_TRUE;
PRBool nsDebugTable::gRflCell = PR_TRUE;
PRBool nsDebugTable::gRflArea = PR_TRUE;
#endif
static PRInt32 gRflCount = 0;
/* ----------- InnerTableReflowState ---------- */
@ -184,6 +168,9 @@ nsTableFrame::nsTableFrame()
nsCRT::memset (mColumnWidths, 0, mColumnWidthsLength*sizeof(PRInt32));
}
#endif
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
NS_IMPL_ADDREF_INHERITED(nsTableFrame, nsHTMLContainerFrame)
@ -259,6 +246,9 @@ nsTableFrame::~nsTableFrame()
delete mTableLayoutStrategy;
mTableLayoutStrategy = nsnull;
}
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
NS_IMETHODIMP
@ -1640,8 +1630,10 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason);
if (nsDebugTable::gRflTable) nsTableFrame::DebugReflow("T::Rfl en", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
// Initialize out parameter
if (nsnull != aDesiredSize.maxElementSize) {
aDesiredSize.maxElementSize->width = 0;
@ -1804,7 +1796,9 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
}
if (nsDebugTable::gRflTable) nsTableFrame::DebugReflow("T::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return rv;
}
@ -4615,32 +4609,10 @@ PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
}
#define INDENT_PER_LEVEL 2
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
void nsTableFrame::DebugGetIndent(const nsIFrame* aFrame,
char* aBuf)
{
PRInt32 numLevels = 0;
nsIFrame* parent = nsnull;
aFrame->GetParent(&parent);
while (parent) {
nsIAtom* frameType = nsnull;
parent->GetFrameType(&frameType);
if ((nsDebugTable::gRflTableOuter && (nsLayoutAtoms::tableOuterFrame == frameType)) ||
(nsDebugTable::gRflTable && (nsLayoutAtoms::tableFrame == frameType)) ||
(nsDebugTable::gRflRowGrp && (nsLayoutAtoms::tableRowGroupFrame == frameType)) ||
(nsDebugTable::gRflRow && (nsLayoutAtoms::tableRowFrame == frameType)) ||
(nsDebugTable::gRflCell && (nsLayoutAtoms::tableCellFrame == frameType)) ||
(nsDebugTable::gRflArea && (nsLayoutAtoms::areaFrame == frameType))) {
numLevels++;
}
NS_IF_RELEASE(frameType);
parent->GetParent(&parent);
}
PRInt32 indent = INDENT_PER_LEVEL * numLevels;
nsCRT::memset (aBuf, ' ', indent);
aBuf[indent] = 0;
}
static PRInt32 gRflCount = 0;
#define INDENT_PER_LEVEL 1
void PrettyUC(nscoord aSize,
char* aBuf)
@ -4653,43 +4625,88 @@ void PrettyUC(nscoord aSize,
}
}
void nsTableFrame::DebugReflow(char* aMessage,
const nsIFrame* aFrame,
const nsHTMLReflowState* aState,
const nsHTMLReflowMetrics* aMetrics,
const nsReflowStatus aStatus)
void GetFrameTypeName(nsIAtom* aFrameType,
char* aName)
{
if (nsLayoutAtoms::tableOuterFrame == aFrameType)
strcpy(aName, "Tbl");
else if (nsLayoutAtoms::tableFrame == aFrameType)
strcpy(aName, "Tbl");
else if (nsLayoutAtoms::tableRowGroupFrame == aFrameType)
strcpy(aName, "RowG");
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
strcpy(aName, "Row");
else if (nsLayoutAtoms::tableCellFrame == aFrameType)
strcpy(aName, "Cell");
else if (nsLayoutAtoms::blockFrame == aFrameType)
strcpy(aName, "Block");
else
NS_ASSERTION(PR_FALSE, "invalid call to GetFrameTypeName");
}
#ifdef DEBUG_TABLE_REFLOW
void DebugGetIndent(const nsIFrame* aFrame,
char* aBuf)
{
PRInt32 numLevels = 0;
nsIFrame* parent = nsnull;
aFrame->GetParent(&parent);
while (parent) {
nsCOMPtr<nsIAtom> frameType;
parent->GetFrameType(getter_AddRefs(frameType));
if ((nsLayoutAtoms::tableOuterFrame == frameType.get()) ||
(nsLayoutAtoms::tableFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowGroupFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowFrame == frameType.get()) ||
(nsLayoutAtoms::tableCellFrame == frameType.get())) {
numLevels++;
}
parent->GetParent(&parent);
}
PRInt32 indent = INDENT_PER_LEVEL * numLevels;
nsCRT::memset (aBuf, ' ', indent);
aBuf[indent] = 0;
}
void nsTableFrame::DebugReflow(nsIFrame* aFrame,
nsHTMLReflowState& aState,
nsHTMLReflowMetrics* aMetrics,
nsReflowStatus aStatus)
{
// get the frame type
nsCOMPtr<nsIAtom> fType;
aFrame->GetFrameType(getter_AddRefs(fType));
char fName[128];
GetFrameTypeName(fType.get(), fName);
char indent[256];
nsTableFrame::DebugGetIndent(aFrame, indent);
printf("%s%s %p ", indent, aMessage, aFrame);
char width[32];
char height[32];
if (aState) {
PrettyUC(aState->availableWidth, width);
PrettyUC(aState->availableHeight, height);
printf("rea=%d av=(%s,%s) ", aState->reason, width, height);
PrettyUC(aState->mComputedWidth, width);
PrettyUC(aState->mComputedHeight, height);
printf("comp=(%s,%s) count=%d \n ", width, height, gRflCount);
DebugGetIndent(aFrame, indent);
printf("%s%s %p ", indent, fName, aFrame);
char width[16];
char height[16];
if (!aMetrics) { // start
PrettyUC(aState.availableWidth, width);
printf("r=%d a=%s ", aState.reason, width);
PrettyUC(aState.mComputedWidth, width);
PrettyUC(aState.mComputedHeight, height);
printf("c=%s,%s cnt=%d \n", width, height, gRflCount);
gRflCount++;
//if (32 == gRflCount) {
// NS_ASSERTION(PR_FALSE, "stop");
//}
}
if (aMetrics) {
if (aState) {
printf("%s", indent);
}
if (aMetrics) { // stop
PrettyUC(aMetrics->width, width);
PrettyUC(aMetrics->height, height);
printf("des=(%s,%s) ", width, height);
printf("d=%s,%s ", width, height);
if (aMetrics->maxElementSize) {
PrettyUC(aMetrics->maxElementSize->width, width);
PrettyUC(aMetrics->maxElementSize->height, height);
printf("maxElem=(%s,%s)", width, height);
printf("me=%s ", width);
}
if (aMetrics->mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
printf("max=%d ", aMetrics->mMaximumWidth);
PrettyUC(aMetrics->mMaximumWidth, width);
printf("m=%s ", width);
}
if (NS_FRAME_COMPLETE != aStatus) {
printf("status=%d", aStatus);
@ -4698,6 +4715,206 @@ void nsTableFrame::DebugReflow(char* aMessage,
}
}
#else
nsReflowTimer* GetFrameTimer(nsIFrame* aFrame,
nsIAtom* aFrameType)
{
if (nsLayoutAtoms::tableOuterFrame == aFrameType)
return ((nsTableOuterFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableFrame == aFrameType)
return ((nsTableFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableRowGroupFrame == aFrameType)
return ((nsTableRowGroupFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
return ((nsTableRowFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableCellFrame == aFrameType)
return ((nsTableCellFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::blockFrame == aFrameType) {
nsIFrame* parentFrame;
aFrame->GetParent(&parentFrame);
nsCOMPtr<nsIAtom> fType;
parentFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableCellFrame == fType) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)parentFrame;
// fix up the block timer, which may be referring to the cell
if (cellFrame->mBlockTimer->mFrame == parentFrame) {
cellFrame->mBlockTimer->mFrame = aFrame;
NS_IF_RELEASE(cellFrame->mBlockTimer->mFrameType);
cellFrame->mBlockTimer->mFrameType = nsLayoutAtoms::blockFrame;
NS_ADDREF(cellFrame->mBlockTimer->mFrameType);
}
return cellFrame->mBlockTimer;
}
}
return nsnull;
}
void DebugReflowPrint(nsReflowTimer& aTimer,
PRUint32 aLevel,
PRBool aSummary)
{
// set up the indentation
char indentChar[128];
PRInt32 indent = INDENT_PER_LEVEL * aLevel;
nsCRT::memset (indentChar, ' ', indent);
indentChar[indent] = 0;
// get the frame type
char fName[128];
GetFrameTypeName(aTimer.mFrameType, fName);
// print the timer
printf("\n%s%s %dms %p", indentChar, fName, aTimer.Elapsed(), aTimer.mFrame);
if (aSummary) {
printf(" times=%d", aTimer.mNumStarts);
}
else {
char avWidth[16];
char compWidth[16];
char compHeight[16];
char desWidth[16];
char desHeight[16];
PrettyUC(aTimer.mAvailWidth, avWidth);
PrettyUC(aTimer.mComputedWidth, compWidth);
PrettyUC(aTimer.mComputedHeight, compHeight);
PrettyUC(aTimer.mDesiredWidth, desWidth);
PrettyUC(aTimer.mDesiredHeight, desHeight);
printf(" r=%d a=%s c=%s,%s d=%s,%s", aTimer.mReason, avWidth, compWidth,
compHeight, desWidth, desHeight);
if (aTimer.mMaxElementWidth >= 0) {
PrettyUC(aTimer.mMaxElementWidth, avWidth);
printf(" me=%s", avWidth);
}
if (aTimer.mMaxWidth >= 0) {
PrettyUC(aTimer.mMaxWidth, avWidth);
printf(" m=%s", avWidth);
}
if (NS_FRAME_COMPLETE != aTimer.mStatus) {
printf(" status=%d", aTimer.mStatus);
}
printf(" cnt=%d", aTimer.mCount);
}
// print the timer's children
nsVoidArray& children = aTimer.mChildren;
PRInt32 numChildren = children.Count();
for (PRInt32 childX = 0; childX < numChildren; childX++) {
nsReflowTimer* child = (nsReflowTimer*)children.ElementAt(childX);
if (child) {
DebugReflowPrint(*child, aLevel + 1, aSummary);
}
else NS_ASSERTION(PR_FALSE, "bad DebugTimeReflow");
}
}
void nsTableFrame::DebugReflow(nsIFrame* aFrame,
nsHTMLReflowState& aState,
nsHTMLReflowMetrics* aMetrics,
nsReflowStatus aStatus)
{
// get the parent timer
const nsHTMLReflowState* parentRS = aState.parentReflowState;
nsReflowTimer* parentTimer = nsnull;
while (parentRS) {
parentTimer = (nsReflowTimer *)parentRS->mDebugHook;
if (parentTimer) break;
parentRS = parentRS->parentReflowState;
}
// get the the frame summary timer
nsCOMPtr<nsIAtom> frameType = nsnull;
aFrame->GetFrameType(getter_AddRefs(frameType));
nsReflowTimer* frameTimer = GetFrameTimer(aFrame, frameType.get());
if (!frameTimer) {
NS_ASSERTION(PR_FALSE, "no frame timer");
return;
}
if (!aMetrics) { // start
// create the reflow timer
nsReflowTimer* timer = new nsReflowTimer(aFrame);
if (!timer) {
NS_ASSERTION(PR_FALSE, "could not create timer");
return;
}
timer->mReason = aState.reason;
timer->mAvailWidth = aState.availableWidth;
timer->mComputedWidth = aState.mComputedWidth;
timer->mComputedHeight = aState.mComputedHeight;
timer->mCount = gRflCount++;
timer->Start();
aState.mDebugHook = timer;
if (parentTimer) {
parentTimer->mChildren.AppendElement(timer);
}
// start the frame summary timer
frameTimer->Start();
}
else {
// stop the reflow timer
nsReflowTimer* timer = (nsReflowTimer *)aState.mDebugHook;
if (timer) {
timer->Stop();
timer->mDesiredWidth = aMetrics->width;
timer->mDesiredHeight = aMetrics->height;
timer->mMaxElementWidth = (aMetrics->maxElementSize)
? aMetrics->maxElementSize->width : -1;
timer->mMaxWidth = (aMetrics->mFlags & NS_REFLOW_CALC_MAX_WIDTH)
? aMetrics->mMaximumWidth : -1;
timer->mStatus = aStatus;
}
else {
NS_ASSERTION(PR_FALSE, "bad DebugTimeReflow");
return;
}
if (!parentTimer) {
// print out all of the reflow timers
DebugReflowPrint(*timer, 0, PR_FALSE);
timer->Destroy();
}
// stop the frame summary timer
frameTimer->Stop();
}
}
void nsTableFrame::DebugReflowDone(nsIFrame* aFrame)
{
// get the timer of aFrame
nsCOMPtr<nsIAtom> frameType = nsnull;
aFrame->GetFrameType(getter_AddRefs(frameType));
nsReflowTimer* thisTimer = GetFrameTimer(aFrame, frameType.get());
// get the nearest ancestor frame with a timer
nsReflowTimer* ancestorTimer;
nsIFrame* ancestorFrame;
aFrame->GetParent(&ancestorFrame);
while (ancestorFrame) {
nsCOMPtr<nsIAtom> frameType = nsnull;
ancestorFrame->GetFrameType(getter_AddRefs(frameType));
ancestorTimer = GetFrameTimer(ancestorFrame, frameType.get());
if (ancestorTimer) break;
ancestorFrame->GetParent(&ancestorFrame);
}
if (ancestorTimer) { // add this timer to its parent
ancestorTimer->mChildren.AppendElement(thisTimer);
nsCOMPtr<nsIAtom> fType;
aFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableCellFrame == fType) {
// add the cell block timer as a child of the cell timer
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aFrame;
cellFrame->mTimer->mChildren.AppendElement(cellFrame->mBlockTimer);
}
}
else { // print out all of the frame timers
printf("\n\nSUMMARY OF REFLOW BY FRAME\n");
DebugReflowPrint(*thisTimer, 0, PR_TRUE);
thisTimer->Destroy();
}
}
#endif
#endif
PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex)
{
PRBool result = PR_FALSE;

View File

@ -46,6 +46,87 @@ struct InnerTableReflowState;
struct nsStylePosition;
struct nsStyleSpacing;
#ifdef DEBUG_TABLE_REFLOW_TIMING
#ifdef WIN32
#include <windows.h>
#endif
class nsReflowTimer
{
public:
nsReflowTimer(nsIFrame* aFrame) {
mFrame = aFrame;
aFrame->GetFrameType(&mFrameType);
Reset();
}
void Destroy() {
PRInt32 numChildren = mChildren.Count();
for (PRInt32 childX = 0; childX < numChildren; childX++) {
((nsReflowTimer*)mChildren.ElementAt(childX))->Destroy();
}
NS_IF_RELEASE(mFrameType);
delete this;
}
void Print(PRUint32 aIndent,
char* aHeader = 0) {
if (aHeader) {
printf("%s", aHeader);
}
printf(" elapsed=%d numStarts=%d \n", Elapsed(), mNumStarts);
}
PRUint32 Elapsed() {
return mTotalTime;
}
void Reset() {
mTotalTime = mNumStarts = 0;
mStarted = PR_FALSE;
}
void Start() {
NS_ASSERTION(!mStarted, "started timer without stopping");
#ifdef WIN32
mStartTime = GetTickCount();
#else
mStartTime = 0;
#endif
mStarted = PR_TRUE;
mNumStarts++;
}
void Stop() {
NS_ASSERTION(mStarted, "stopped timer without starting");
mTotalTime += GetTickCount() - mStartTime;
mStarted = PR_FALSE;
}
PRUint32 mTotalTime;
PRUint32 mStartTime;
PRUint32 mNumStarts;
PRBool mStarted;
const nsIFrame* mFrame;
nsIAtom* mFrameType; // needed for frame summary timer
nsReflowReason mReason;
nsVoidArray mChildren;
PRInt32 mCount;
// reflow state/reflow metrics data
nscoord mAvailWidth;
nscoord mComputedWidth;
nscoord mComputedHeight;
nscoord mMaxElementWidth;
nscoord mMaxWidth; // preferred width
nscoord mDesiredWidth;
nscoord mDesiredHeight;
nsReflowStatus mStatus;
private:
~nsReflowTimer() {}
};
#endif
/**
* Child list name indices
* @see #GetAdditionalChildListName()
@ -53,15 +134,6 @@ struct nsStyleSpacing;
#define NS_TABLE_FRAME_COLGROUP_LIST_INDEX 0
#define NS_TABLE_FRAME_LAST_LIST_INDEX NS_TABLE_FRAME_COLGROUP_LIST_INDEX
struct nsDebugTable
{
static PRBool gRflTableOuter;
static PRBool gRflTable;
static PRBool gRflRowGrp;
static PRBool gRflRow;
static PRBool gRflCell;
static PRBool gRflArea;
};
/* ============================================================================ */
/** nsTableFrame maps the inner portion of a table (everything except captions.)
@ -416,15 +488,6 @@ public:
PRBool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(PRBool aValue);
static void DebugReflow(char* aMessage,
const nsIFrame* aFrame,
const nsHTMLReflowState* aState,
const nsHTMLReflowMetrics* aMetrics,
const nsReflowStatus aStatus = NS_FRAME_COMPLETE);
static void DebugGetIndent(const nsIFrame* aFrame,
char* aBuf);
protected:
/** protected constructor.
@ -873,6 +936,19 @@ protected:
// used only for the collapsing border model
nscoord mPercentBasisForRows;
nscoord mPreferredWidth;
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
public:
static void DebugReflow(nsIFrame* aFrame,
nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics* aMetrics = nsnull,
nsReflowStatus aStatus = NS_FRAME_COMPLETE);
#ifdef DEBUG_TABLE_REFLOW_TIMING
static void DebugReflowDone(nsIFrame* aFrame);
nsReflowTimer* mTimer;
#endif
#endif
};

View File

@ -95,10 +95,16 @@ NS_IMPL_RELEASE_INHERITED(nsTableOuterFrame, nsHTMLContainerFrame)
nsTableOuterFrame::nsTableOuterFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
nsTableOuterFrame::~nsTableOuterFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
nsresult nsTableOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
@ -1390,7 +1396,9 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame", aOuterRS.reason);
if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl en", this, &aOuterRS, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS);
#endif
nsresult rv = NS_OK;
PRUint8 captionSide = GetCaptionSide();
@ -1499,7 +1507,9 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext,
}
}
if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS, &aDesiredSize, aStatus);
#endif
return rv;
}

View File

@ -27,6 +27,10 @@
#include "nsBlockFrame.h"
#include "nsITableLayout.h"
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
#endif
struct nsStyleTable;
class nsTableCaptionFrame : public nsBlockFrame
@ -354,6 +358,11 @@ private:
nsSize mMaxElementSize;
nscoord mInnerTableMaximumWidth;
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
#endif
};
inline nscoord nsTableOuterFrame::GetMinCaptionWidth()

View File

@ -115,6 +115,16 @@ nsTableRowFrame::nsTableRowFrame()
mBits.mMinRowSpan = 1;
mBits.mRowIndex = 0;
ResetTallestCell(0);
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
nsTableRowFrame::~nsTableRowFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
NS_IMETHODIMP
@ -1488,7 +1498,9 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame", aReflowState.reason);
if (nsDebugTable::gRflRow) nsTableFrame::DebugReflow("TR::Rfl en", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
nsresult rv = NS_OK;
// Initialize 'out' parameters (aStatus set below, undefined if rv returns an error)
@ -1548,7 +1560,9 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
mMaxElementSize = *aDesiredSize.maxElementSize;
}
if (nsDebugTable::gRflRow) nsTableFrame::DebugReflow("TR::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return rv;
}

View File

@ -28,6 +28,10 @@
class nsTableFrame;
class nsTableCellFrame;
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
#endif
/* ----------- RowReflowState ---------- */
struct RowReflowState {
@ -71,6 +75,8 @@ struct RowReflowState {
class nsTableRowFrame : public nsHTMLContainerFrame
{
public:
virtual ~nsTableRowFrame();
NS_IMETHOD Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
@ -321,6 +327,11 @@ private:
// max-ascent and max-descent amongst all cells that have 'vertical-align: baseline'
nscoord mMaxCellAscent; // does include cells with rowspan > 1
nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
#endif
};
inline PRInt32 nsTableRowFrame::GetRowIndex() const

View File

@ -42,6 +42,20 @@
#include "nsCellMap.h"//table cell navigation
nsTableRowGroupFrame::nsTableRowGroupFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
}
nsTableRowGroupFrame::~nsTableRowGroupFrame()
{
#ifdef DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflowDone(this);
#endif
}
/* ----------- nsTableRowGroupFrame ---------- */
nsrefcnt nsTableRowGroupFrame::AddRef(void)
{
@ -1055,7 +1069,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame", aReflowState.reason);
if (nsDebugTable::gRflRowGrp) nsTableFrame::DebugReflow("TRG::Rfl", this, &aReflowState, nsnull);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif
nsresult rv=NS_OK;
// Initialize out parameter
@ -1163,7 +1179,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
mMaxElementSize = *aDesiredSize.maxElementSize;
}
if (nsDebugTable::gRflRowGrp) nsTableFrame::DebugReflow("TRG::Rfl ex", this, nsnull, &aDesiredSize, aStatus);
#if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
return rv;
}

View File

@ -29,6 +29,9 @@
class nsTableFrame;
class nsTableRowFrame;
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
#endif
/* ----------- RowGroupReflowState ---------- */
@ -103,6 +106,7 @@ public:
*/
friend nsresult
NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
virtual ~nsTableRowGroupFrame();
NS_IMETHOD AppendFrames(nsIPresContext* aPresContext,
nsIPresShell& aPresShell,
@ -223,6 +227,7 @@ public:
protected:
nsTableRowGroupFrame();
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@ -341,6 +346,10 @@ public:
private:
nsSize mMaxElementSize;
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
#endif
};
inline void nsTableRowGroupFrame::GetMaxElementSize(nsSize& aMaxElementSize) const