diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp
index ca74d55ba83..736326dbbc3 100644
--- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp
@@ -145,6 +145,30 @@ PRInt32 nsTableCellFrame::GetRowSpan()
return result;
}
+/** helper method to get the col span of this frame's content (which must be a cell) */
+PRInt32 nsTableCellFrame::GetColSpan()
+{
+ PRInt32 result = 0;
+ nsTableCell *cellContent = (nsTableCell *)mContent;
+ if (nsnull!=cellContent)
+ {
+ result = cellContent->GetColSpan();
+ }
+ return result;
+}
+
+/** helper method to get the col index of this frame's content (which must be a cell) */
+PRInt32 nsTableCellFrame::GetColIndex()
+{
+ PRInt32 result = 0;
+ nsTableCell *cellContent = (nsTableCell *)mContent;
+ if (nsnull!=cellContent)
+ {
+ result = cellContent->GetColIndex();
+ }
+ return result;
+}
+
void nsTableCellFrame::CreatePsuedoFrame(nsIPresContext* aPresContext)
{
// Do we have a prev-in-flow?
@@ -229,6 +253,8 @@ NS_METHOD nsTableCellFrame::ResizeReflow(nsIPresContext* aPresContext,
// Try to reflow the child into the available space. It might not
// fit or might need continuing.
+ if (availSize.height < 0)
+ availSize.height = 1;
nsSize maxKidElementSize;
if (gsDebug==PR_TRUE)
printf(" nsTableCellFrame::ResizeReflow calling ReflowChild with availSize=%d,%d\n",
diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h
index 3199b6efa5d..65daa2c299a 100644
--- a/mozilla/layout/html/table/src/nsTableCellFrame.h
+++ b/mozilla/layout/html/table/src/nsTableCellFrame.h
@@ -63,8 +63,15 @@ public:
void VerticallyAlignChild(nsIPresContext* aPresContext);
+ /** return the mapped cell's row span. Always >= 1. */
virtual PRInt32 GetRowSpan();
+ /** return the mapped cell's col span. Always >= 1. */
+ virtual PRInt32 GetColSpan();
+
+ /** return the mapped cell's column index (starting at 0 for the first column) */
+ virtual PRInt32 GetColIndex();
+
virtual ~nsTableCellFrame();
protected:
diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp
index e4de2748789..f34bd8818ce 100644
--- a/mozilla/layout/html/table/src/nsTableFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableFrame.cpp
@@ -90,6 +90,12 @@ struct InnerTableReflowState {
// Flag for whether we're dealing with the first interior row group
PRBool firstRowGroup;
+ // a list of the footers in this table frame, for quick access when inserting bodies
+ nsVoidArray *footerList;
+
+ // cache the total height of the footers for placing body rows
+ nscoord footerHeight;
+
InnerTableReflowState(nsIPresContext* aPresContext,
const nsSize& aMaxSize,
nsStyleMolecule* aMol)
@@ -103,9 +109,13 @@ struct InnerTableReflowState {
unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
firstRowGroup = PR_TRUE;
+ footerHeight = 0;
+ footerList = nsnull;
}
~InnerTableReflowState() {
+ if (nsnull!=footerList)
+ delete footerList;
}
};
@@ -712,7 +722,7 @@ nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresCont
nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
#ifdef NS_DEBUG
- PreReflowCheck();
+ //PreReflowCheck();
#endif
// Initialize out parameter
@@ -775,7 +785,7 @@ nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresCont
}
// Return our desired rect
- NS_ASSERTION(0GetRowGroupType(kidType);
+ if (tFootTag==kidType)
+ {
+ if (nsnull==aState.footerList)
+ aState.footerList = new nsVoidArray();
+ aState.footerList->AppendElement((void *)aKidFrame);
+ aState.footerHeight += aKidRect.height;
+ }
+ // else if this is a body row group, push down all the footer row groups
+ else
+ {
+ // don't bother unless there are footers to push down
+ if (nsnull!=aState.footerList && 0!=aState.footerList->Count())
+ {
+ nsPoint origin;
+ aKidFrame->GetOrigin(origin);
+ origin.y -= aState.footerHeight;
+ aKidFrame->MoveTo(origin.x, origin.y);
+ nsIAtom * tBodyTag = NS_NewAtom(nsTablePart::kRowGroupBodyTagString); // tBodyTag: REFCNT++
+ if (tBodyTag==kidType)
+ {
+ PRInt32 numFooters = aState.footerList->Count();
+ for (PRInt32 footerIndex = 0; footerIndex < numFooters; footerIndex++)
+ {
+ nsTableRowGroupFrame * footer = (nsTableRowGroupFrame *)(aState.footerList->ElementAt(footerIndex));
+ NS_ASSERTION(nsnull!=footer, "bad footer list in table inner frame.");
+ if (nsnull!=footer)
+ {
+ footer->GetOrigin(origin);
+ origin.y += aKidRect.height;
+ footer->MoveTo(origin.x, origin.y);
+ }
+ }
+ }
+ NS_RELEASE(tBodyTag);
+ }
+ }
+ NS_RELEASE(tFootTag);
+
// Update the maximum element size
if (PR_TRUE==aState.firstRowGroup)
{
@@ -1284,8 +1336,8 @@ PRBool nsTableFrame::PullUpChildren(nsIPresContext* aPresContext,
*/
nsIFrame::ReflowStatus
nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext,
- InnerTableReflowState& aState,
- nsSize* aMaxElementSize)
+ InnerTableReflowState& aState,
+ nsSize* aMaxElementSize)
{
#ifdef NS_DEBUG
VerifyLastIsComplete();
@@ -2441,16 +2493,53 @@ NS_METHOD nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
cf->SetRect(nsRect(0, 0, mRect.width, 0));
// add headers and footers to cf
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
- PRInt32 childCount;
-
- firstInFlow->ChildCount(childCount);
- PRInt32 childIndex = 0;
- for (; childIndex < childCount; childIndex++)
+ nsIFrame * rg = nsnull;
+ firstInFlow->ChildAt(0, rg);
+ NS_ASSERTION (nsnull!=rg, "previous frame has no children");
+ nsIAtom * tHeadTag = NS_NewAtom(nsTablePart::kRowGroupHeadTagString); // tHeadTag: REFCNT++
+ nsIAtom * tFootTag = NS_NewAtom(nsTablePart::kRowGroupFootTagString); // tFootTag: REFCNT++
+ PRInt32 index = 0;
+ nsIFrame * bodyRowGroupFromOverflow = mOverflowList;
+ nsIFrame * lastSib = nsnull;
+ for ( ; nsnull!=rg; index++)
{
- // TODO: place copies of the header and footer row groups here
- // maybe need to do this in ResizeReflow at the beginning, when we determine we are a continuing frame
+ nsIContent *content = nsnull;
+ rg->GetContent(content); // content: REFCNT++
+ NS_ASSERTION(nsnull!=content, "bad frame, returned null content.");
+ nsIAtom * rgTag = content->GetTag();
+ // if we've found a header or a footer, replicate it
+ if (tHeadTag==rgTag || tFootTag==rgTag)
+ {
+ printf("found a head or foot in continuing frame\n");
+ // Resolve style for the child
+ nsIStyleContext* kidStyleContext =
+ aPresContext->ResolveStyleContextFor(content, cf); // kidStyleContext: REFCNT++
+ nsStyleMolecule* kidMol =
+ (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
+ nsIContentDelegate* kidDel = nsnull;
+ kidDel = content->GetDelegate(aPresContext); // kidDel: REFCNT++
+ nsIFrame * duplicateFrame = kidDel->CreateFrame(aPresContext, content, index, cf);
+ NS_RELEASE(kidDel); // kidDel: REFCNT--
+ duplicateFrame->SetStyleContext(kidStyleContext);
+ NS_RELEASE(kidStyleContext); // kidStyleContenxt: REFCNT--
+
+ if (nsnull==lastSib)
+ {
+ mOverflowList = duplicateFrame;
+ }
+ else
+ {
+ lastSib->SetNextSibling(duplicateFrame);
+ }
+ duplicateFrame->SetNextSibling(bodyRowGroupFromOverflow);
+ lastSib = duplicateFrame;
+ }
+ NS_RELEASE(content); // content: REFCNT--
+ // get the next row group
+ rg->GetNextSibling(rg);
}
-
+ NS_RELEASE(tFootTag); // tHeadTag: REFCNT --
+ NS_RELEASE(tHeadTag); // tFootTag: REFCNT --
aContinuingFrame = cf;
return NS_OK;
}
diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp
index 2439865157f..a33de28ae1f 100644
--- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp
@@ -305,7 +305,13 @@ NS_METHOD nsTableOuterFrame::ResizeReflow(nsIPresContext* aPresContext,
//NS_ASSERTION(0 aState.availSize.height) && (kidFrame != mFirstChild)) {
- // The child is too wide to fit in the available space, and it's
+ // The child is too tall to fit in the available space, and it's
// not our first child
// Since we are giving the next-in-flow our last child, we
@@ -518,8 +524,6 @@ PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContex
// Update mLastContentIsComplete now that this kid fits
mLastContentIsComplete = PRBool(status == frComplete);
- // Is the child complete?
- mLastContentIsComplete = PRBool(status == frComplete);
if (frNotComplete == status) {
// No, the child isn't complete
nsIFrame* kidNextInFlow;
@@ -555,6 +559,21 @@ PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContex
kidFrame->GetNextSibling(nextSibling);
if (nsnull != nextSibling) {
PushChildren(nextSibling, kidFrame, lastContentIsComplete);
+ /* debug */
+ /*
+ printf ("having just pushed children, here is the frame hierarchy.\n");
+ nsIFrame *p;
+ GetGeometricParent(p);
+ nsIFrame *root;
+ while (nsnull!=p)
+ {
+ root = p;
+ p->GetGeometricParent(p);
+ }
+ root->List();
+ fflush(stdout);
+ */
+ /* end debug */
SetLastContentOffset(prevKidFrame);
}
result = PR_FALSE;
diff --git a/mozilla/layout/html/table/src/nsTablePart.cpp b/mozilla/layout/html/table/src/nsTablePart.cpp
index dfd8ccae9d4..80099be0d52 100644
--- a/mozilla/layout/html/table/src/nsTablePart.cpp
+++ b/mozilla/layout/html/table/src/nsTablePart.cpp
@@ -593,7 +593,7 @@ PRBool nsTablePart::AppendRowGroup (nsTableRowGroup *aContent)
// if aContent is a body and the current child is a footer, stop, we've found the spot
else if (tBodyTag==rowGroupTag && tFootTag==tableChildTag)
{
- break;
+ continue;
}
// if aContent is a body and we've gotten this far, keep going
else if (tBodyTag==rowGroupTag)
diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp
index 2af64ea1fb8..318e92d5cbb 100644
--- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp
@@ -40,9 +40,61 @@ static const PRBool gsDebug2 = PR_FALSE;
static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
+/* ----------- RowReflowState ---------- */
+
+struct RowReflowState {
+
+ // The body's style molecule
+ nsStyleMolecule* mol;
+
+ // The body's available size (computed from the body's parent)
+ nsSize availSize;
+
+ // Margin tracking information
+ nscoord prevMaxPosBottomMargin;
+ nscoord prevMaxNegBottomMargin;
+
+ // Flags for whether the max size is unconstrained
+ PRBool unconstrainedWidth;
+ PRBool unconstrainedHeight;
+
+ // Running x-offset
+ nscoord x;
+
+ // Height of tallest cell (excluding cells with rowspan>1)
+ nscoord maxCellHeight;
+
+ nsTableFrame *tableFrame;
+
+
+ RowReflowState( nsIPresContext* aPresContext,
+ const nsSize& aMaxSize,
+ nsStyleMolecule* aMol)
+ {
+ mol = aMol;
+ availSize.width = aMaxSize.width;
+ availSize.height = aMaxSize.height;
+ prevMaxPosBottomMargin = 0;
+ prevMaxNegBottomMargin = 0;
+ x=0;
+ unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
+ unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
+ maxCellHeight=0;
+ tableFrame = nsnull;
+ }
+
+ ~RowReflowState() {
+ }
+};
+
+
+
+
+/* ----------- nsTableRowpFrame ---------- */
+
nsTableRowFrame::nsTableRowFrame(nsIContent* aContent,
- PRInt32 aIndexInParent,
- nsIFrame* aParentFrame)
+ PRInt32 aIndexInParent,
+ nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aIndexInParent, aParentFrame),
mTallestCell(0)
{
@@ -120,17 +172,759 @@ PRInt32 nsTableRowFrame::GetTallestChild() const
return mTallestCell;
}
-/*
+// Collapse child's top margin with previous bottom margin
+nscoord nsTableRowFrame::GetTopMarginFor( nsIPresContext* aCX,
+ RowReflowState& aState,
+ nsStyleMolecule* aKidMol)
+{
+ nscoord margin;
+ nscoord maxNegTopMargin = 0;
+ nscoord maxPosTopMargin = 0;
+ if ((margin = aKidMol->margin.top) < 0) {
+ maxNegTopMargin = -margin;
+ } else {
+ maxPosTopMargin = margin;
+ }
-want to use min space the child can fit in to
-determine its real size, unless fixed columns sizes
-are present.
+ nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin);
+ nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin);
+ margin = maxPos - maxNeg;
+
+ return margin;
+}
+
+// Position and size aKidFrame and update our reflow state. The origin of
+// aKidRect is relative to the upper-left origin of our frame, and includes
+// any left/top margin.
+void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsIFrame* aKidFrame,
+ const nsRect& aKidRect,
+ nsSize* aMaxElementSize,
+ nsSize& aKidMaxElementSize)
+{
+ if (PR_TRUE==gsDebug1)
+ printf ("row: placing cell at %d, %d, %d, %d\n",
+ aKidRect.x, aKidRect.y, aKidRect.width, aKidRect.height);
+
+ // Place and size the child
+ aKidFrame->SetRect(aKidRect);
+
+ // Update the maximum element size
+ PRInt32 rowSpan = ((nsTableCellFrame*)aKidFrame)->GetRowSpan();
+ if (nsnull != aMaxElementSize) {
+ aMaxElementSize->width += aKidMaxElementSize.width;
+ if ((1==rowSpan) && (aKidMaxElementSize.height>aMaxElementSize->height))
+ {
+ aMaxElementSize->height = aKidMaxElementSize.height;
+ }
+ }
+ if ((1==rowSpan) && (aState.maxCellHeightmFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ NS_PRECONDITION(nsnull != mFirstChild, "no children");
+
+ PRInt32 childCount = 0;
+ nsIFrame* prevKidFrame = nsnull;
+
+ // Remember our original mLastContentIsComplete so that if we end up
+ // having to push children, we have the correct value to hand to
+ // PushChildren.
+ PRBool lastContentIsComplete = mLastContentIsComplete;
+
+ nsSize kidMaxElementSize;
+ nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
+ PRBool result = PR_TRUE;
+
+ for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
+ nsIContent* cell = nsnull;
+ kidFrame->GetContent(cell); // cell: REFCNT++
+ nsSize kidAvailSize(aState.availSize);
+ if (0>=kidAvailSize.height)
+ kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet
+ nsReflowMetrics desiredSize;
+ nsIFrame::ReflowStatus status;
+
+ // Get top margin for this kid
+ nsIStyleContext* kidSC;
+ kidFrame->GetStyleContext(aPresContext, kidSC);
+ nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+ nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
+ nscoord bottomMargin = kidMol->margin.bottom;
+ NS_RELEASE(kidSC);
+
+ // Figure out the amount of available size for the child (subtract
+ // off the top margin we are going to apply to it)
+ if (PR_FALSE == aState.unconstrainedHeight) {
+ kidAvailSize.height -= topMargin;
+ }
+ // Subtract off for left and right margin
+ if (PR_FALSE == aState.unconstrainedWidth) {
+ kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
+ }
+
+ if (NS_UNCONSTRAINEDSIZE == aState.availSize.width)
+ {
+ // Reflow the child into the available space
+ status = ReflowChild(kidFrame, aPresContext, desiredSize,
+ kidAvailSize, pKidMaxElementSize);
+ nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize);
+ aState.tableFrame->SetCellLayoutData(&kidLayoutData, (nsTableCell *)cell);
+ }
+ else
+ { // we're in a constrained situation, so get the avail width from the known column widths
+ nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell);
+ PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex();
+ PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan();
+ nscoord availWidth = 0;
+ for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
+ NS_ASSERTION(0width, pKidMaxElementSize->height);
+ else
+ printf("reflow of cell returned result = %s with desired=%d,%d, min = nsnull\n",
+ status==frComplete?"complete":"NOT complete",
+ desiredSize.width, desiredSize.height);
+ }
+ }
+ NS_RELEASE(cell); // cell: REFCNT--
+ // Did the child fit?
+ if ((kidFrame != mFirstChild) &&
+ ((kidAvailSize.height <= 0) ||
+ (desiredSize.height > kidAvailSize.height)))
+ {
+ // The child's height is too big to fit at all in our remaining space,
+ // and it's not our first child.
+
+ // Since we are giving the next-in-flow our last child, we
+ // give it our original mLastContentIsComplete, too (in case we
+ // are pushing into an empty next-in-flow)
+ PushChildren(kidFrame, prevKidFrame, lastContentIsComplete);
+ SetLastContentOffset(prevKidFrame);
+
+ // Our mLastContentIsComplete was already set by the last kid we
+ // reflowed reflow's status
+ result = PR_FALSE;
+ break;
+ }
+
+ // Adjust the running x-offset, taking into account intruders (cells from prior rows with rowspans > 1)
+ aState.x = 0;
+ PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
+ for (PRInt32 colIndex=0; colIndexGetColumnWidth(colIndex);
+ // Place the child after taking into account it's margin
+ nsRect kidRect (aState.x, topMargin, desiredSize.width, desiredSize.height);
+ PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize,
+ kidMaxElementSize);
+ if (bottomMargin < 0) {
+ aState.prevMaxNegBottomMargin = -bottomMargin;
+ } else {
+ aState.prevMaxPosBottomMargin = bottomMargin;
+ }
+ childCount++;
+
+ // Remember where we just were in case we end up pushing children
+ prevKidFrame = kidFrame;
+
+ // Update mLastContentIsComplete now that this kid fits
+ mLastContentIsComplete = PRBool(status == frComplete);
+
+ /* Rows should not create continuing frames for cells
+ * unless they absolutely have to!
+ * check to see if this is absolutely necessary (with new params from troy)
+ * otherwise PushChildren and bail.
+ */
+ // Special handling for incomplete children
+ if (frNotComplete == status) {
+ // XXX It's good to assume that we might still have room
+ // even if the child didn't complete (floaters will want this)
+ nsIFrame* kidNextInFlow;
+
+ kidFrame->GetNextInFlow(kidNextInFlow);
+ PRBool lastContentIsComplete = mLastContentIsComplete;
+ if (nsnull == kidNextInFlow) {
+ // No the child isn't complete, and it doesn't have a next in flow so
+ // create a continuing frame. This hooks the child into the flow.
+ nsIFrame* continuingFrame;
+
+ kidFrame->CreateContinuingFrame(aPresContext, this, continuingFrame);
+
+ // Insert the frame. We'll reflow it next pass through the loop
+ nsIFrame* nextSib;
+
+ kidFrame->GetNextSibling(nextSib);
+ continuingFrame->SetNextSibling(nextSib);
+ kidFrame->SetNextSibling(continuingFrame);
+ if (nsnull == nextSib) {
+ // Assume that the continuation frame we just created is
+ // complete, for now. It will get reflowed by our
+ // next-in-flow (we are going to push it now)
+ lastContentIsComplete = PR_TRUE;
+ }
+ }
+ // We've used up all of our available space so push the remaining
+ // children to the next-in-flow
+ nsIFrame* nextSibling;
+
+ kidFrame->GetNextSibling(nextSibling);
+ if (nsnull != nextSibling) {
+ PushChildren(nextSibling, kidFrame, lastContentIsComplete);
+ SetLastContentOffset(prevKidFrame);
+ }
+ result = PR_FALSE;
+ break;
+ }
+
+ // Add back in the left and right margins, because one row does not
+ // impact another row's width
+ if (PR_FALSE == aState.unconstrainedWidth) {
+ kidAvailSize.width += kidMol->margin.left + kidMol->margin.right;
+ }
+
+ // Get the next child
+ kidFrame->GetNextSibling(kidFrame);
+
+ }
+
+ SetMaxChildHeight(aState.maxCellHeight); // remember height of tallest child who doesn't have a row span
+
+ // Update the child count
+ mChildCount = childCount;
+
+#ifdef NS_DEBUG
+ NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count");
+
+ nsIFrame* lastChild;
+ PRInt32 lastIndexInParent;
+
+ LastChild(lastChild);
+ lastChild->GetIndexInParent(lastIndexInParent);
+ NS_POSTCONDITION(lastIndexInParent == mLastContentOffset, "bad last content offset");
+#endif
+
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+ ListTag(stdout);
+ printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n",
+ (result ? "" : "NOT "),
+ mChildCount,
+ mFirstContentOffset, mLastContentOffset,
+ (mLastContentIsComplete ? 'T' : 'F'));
+#ifdef NOISY_FLOW
+ {
+ nsTableRowFrame* flow = (nsTableRowFrame*) mNextInFlow;
+ while (flow != 0) {
+ printf(" %p: [%d,%d,%c]\n",
+ flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ return result;
+}
+
+/**
+ * Try and pull-up frames from our next-in-flow
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return true if we successfully pulled-up all the children and false
+ * otherwise, e.g. child didn't fit
+ */
+PRBool nsTableRowFrame::PullUpChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize)
+{
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+ ListTag(stdout);
+ printf(": pullup (childCount=%d) [%d,%d,%c]\n",
+ mChildCount,
+ mFirstContentOffset, mLastContentOffset,
+ (mLastContentIsComplete ? 'T' : 'F'));
+#ifdef NOISY_FLOW
+ {
+ nsTableRowFrame* flow = (nsTableRowFrame*) mNextInFlow;
+ while (flow != 0) {
+ printf(" %p: [%d,%d,%c]\n",
+ flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ nsTableRowFrame* nextInFlow = (nsTableRowFrame*)mNextInFlow;
+ nsSize kidMaxElementSize;
+ nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
+ nsSize kidAvailSize(aState.availSize);
+#ifdef NS_DEBUG
+ PRInt32 kidIndex = NextChildOffset();
+#endif
+ nsIFrame* prevKidFrame;
+
+ LastChild(prevKidFrame);
+
+ // This will hold the prevKidFrame's mLastContentIsComplete
+ // status. If we have to push the frame that follows prevKidFrame
+ // then this will become our mLastContentIsComplete state. Since
+ // prevKidFrame is initially our last frame, it's completion status
+ // is our mLastContentIsComplete value.
+ PRBool prevLastContentIsComplete = mLastContentIsComplete;
+
+ PRBool result = PR_TRUE;
+
+ while (nsnull != nextInFlow) {
+ nsReflowMetrics desiredSize;
+ ReflowStatus status;
+
+ // Get the next child
+ nsIFrame* kidFrame = nextInFlow->mFirstChild;
+
+ // Any more child frames?
+ if (nsnull == kidFrame) {
+ // No. Any frames on its overflow list?
+ if (nsnull != nextInFlow->mOverflowList) {
+ // Move the overflow list to become the child list
+// NS_ABORT();
+ nextInFlow->AppendChildren(nextInFlow->mOverflowList);
+ nextInFlow->mOverflowList = nsnull;
+ kidFrame = nextInFlow->mFirstChild;
+ } else {
+ // We've pulled up all the children, so move to the next-in-flow.
+ nextInFlow->GetNextInFlow((nsIFrame*&)nextInFlow);
+ continue;
+ }
+ }
+
+ // See if the child fits in the available space. If it fits or
+ // it's splittable then reflow it. The reason we can't just move
+ // it is that we still need ascent/descent information
+ nsSize kidFrameSize;
+ SplittableType kidIsSplittable;
+
+ kidFrame->GetSize(kidFrameSize);
+ kidFrame->IsSplittable(kidIsSplittable);
+
+ if ((kidFrameSize.height > aState.availSize.height) &&
+ (kidIsSplittable == frNotSplittable)) {
+ result = PR_FALSE;
+ mLastContentIsComplete = prevLastContentIsComplete;
+ break;
+ }
+
+ nsIContent *cell = nsnull;
+ kidFrame->GetContent(cell); // cell: REFNCT++
+ // we're in a constrained situation, so get the avail width from the known column widths
+ nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell);
+ PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex();
+ PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan();
+ nscoord availWidth = 0;
+ for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
+ NS_ASSERTION(0width, pKidMaxElementSize->height);
+ else
+ printf("reflow of cell returned result = %s with desired=%d,%d, min = nsnull\n",
+ status==frComplete?"complete":"NOT complete",
+ desiredSize.width, desiredSize.height);
+ }
+ }
+ NS_RELEASE(cell); // cell: REFCNT--
+
+ // Did the child fit?
+ if ((desiredSize.height > aState.availSize.height) && (nsnull != mFirstChild)) {
+ // The child is too tall to fit in the available space, and it's
+ // not our first child
+ result = PR_FALSE;
+ mLastContentIsComplete = prevLastContentIsComplete;
+ break;
+ }
+
+ // Adjust the running x-offset, taking into account intruders (cells from prior rows with rowspans > 1)
+ aState.x = 0;
+ PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
+ for (PRInt32 colIndex=0; colIndexGetColumnWidth(colIndex);
+ // Place the child
+ //nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
+ nsRect kidRect (aState.x, 0, desiredSize.width, desiredSize.height);
+ PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize);
+
+ // Remove the frame from its current parent
+ kidFrame->GetNextSibling(nextInFlow->mFirstChild);
+ nextInFlow->mChildCount--;
+ // Update the next-in-flows first content offset
+ if (nsnull != nextInFlow->mFirstChild) {
+ nextInFlow->SetFirstContentOffset(nextInFlow->mFirstChild);
+ }
+
+ // Link the frame into our list of children
+ kidFrame->SetGeometricParent(this);
+ nsIFrame* kidContentParent;
+
+ kidFrame->GetContentParent(kidContentParent);
+ if (nextInFlow == kidContentParent) {
+ kidFrame->SetContentParent(this);
+ }
+ if (nsnull == prevKidFrame) {
+ mFirstChild = kidFrame;
+ SetFirstContentOffset(kidFrame);
+ } else {
+ prevKidFrame->SetNextSibling(kidFrame);
+ }
+ kidFrame->SetNextSibling(nsnull);
+ mChildCount++;
+
+ // Remember where we just were in case we end up pushing children
+ prevKidFrame = kidFrame;
+ prevLastContentIsComplete = mLastContentIsComplete;
+
+ // Is the child we just pulled up complete?
+ mLastContentIsComplete = PRBool(status == frComplete);
+ if (frNotComplete == status) {
+ // No the child isn't complete
+ nsIFrame* kidNextInFlow;
+
+ kidFrame->GetNextInFlow(kidNextInFlow);
+ if (nsnull == kidNextInFlow) {
+ // The child doesn't have a next-in-flow so create a
+ // continuing frame. The creation appends it to the flow and
+ // prepares it for reflow.
+ nsIFrame* continuingFrame;
+
+ kidFrame->CreateContinuingFrame(aPresContext, this, continuingFrame);
+ NS_ASSERTION(nsnull != continuingFrame, "frame creation failed");
+
+ // Add the continuing frame to our sibling list and then push
+ // it to the next-in-flow. This ensures the next-in-flow's
+ // content offsets and child count are set properly. Note that
+ // we can safely assume that the continuation is complete so
+ // we pass PR_TRUE into PushChidren in case our next-in-flow
+ // was just drained and now needs to know it's
+ // mLastContentIsComplete state.
+ kidFrame->SetNextSibling(continuingFrame);
+
+ PushChildren(continuingFrame, kidFrame, PR_TRUE);
+
+ // After we push the continuation frame we don't need to fuss
+ // with mLastContentIsComplete beause the continuation frame
+ // is no longer on *our* list.
+ }
+
+ // If the child isn't complete then it means that we've used up
+ // all of our available space.
+ result = PR_FALSE;
+ break;
+ }
+ }
+
+ // Update our last content offset
+ if (nsnull != prevKidFrame) {
+ NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child");
+ SetLastContentOffset(prevKidFrame);
+ }
+
+ // We need to make sure the first content offset is correct for any empty
+ // next-in-flow frames (frames where we pulled up all the child frames)
+ nextInFlow = (nsTableRowFrame*)mNextInFlow;
+ if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) {
+ // We have at least one empty frame. Did we succesfully pull up all the
+ // child frames?
+ if (PR_FALSE == result) {
+ // No, so we need to adjust the first content offset of all the empty
+ // frames
+ AdjustOffsetOfEmptyNextInFlows();
+#ifdef NS_DEBUG
+ } else {
+ // Yes, we successfully pulled up all the child frames which means all
+ // the next-in-flows must be empty. Do a sanity check
+ while (nsnull != nextInFlow) {
+ NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow");
+ nextInFlow->GetNextInFlow((nsIFrame*&)nextInFlow);
+ }
+#endif
+ }
+ }
+
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+
+#ifdef NOISY
+ ListTag(stdout);
+ printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n",
+ (result ? "" : "NOT "),
+ mChildCount,
+ mFirstContentOffset, mLastContentOffset,
+ (mLastContentIsComplete ? 'T' : 'F'));
+#ifdef NOISY_FLOW
+ {
+ nsTableRowFrame* flow = (nsTableRowFrame*) mNextInFlow;
+ while (flow != 0) {
+ printf(" %p: [%d,%d,%c]\n",
+ flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ return result;
+}
+
+/**
+ * Create new frames for content we haven't yet mapped
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return frComplete if all content has been mapped and frNotComplete
+ * if we should be continued
+ */
+nsIFrame::ReflowStatus
+nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize)
+{
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+ nsIFrame* kidPrevInFlow = nsnull;
+ ReflowStatus result = frNotComplete;
+
+ // If we have no children and we have a prev-in-flow then we need to pick
+ // up where it left off. If we have children, e.g. we're being resized, then
+ // our content offset should already be set correctly...
+ if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) {
+ nsTableRowFrame* prev = (nsTableRowFrame*)mPrevInFlow;
+ NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow");
+
+ mFirstContentOffset = prev->NextChildOffset();
+ if (!prev->mLastContentIsComplete) {
+ // Our prev-in-flow's last child is not complete
+ prev->LastChild(kidPrevInFlow);
+ }
+ }
+
+ mLastContentIsComplete = PR_TRUE;
+
+ // Place our children, one at a time, until we are out of children
+ nsSize kidMaxElementSize;
+ nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
+ nsSize kidAvailSize(aState.availSize);
+ PRInt32 kidIndex = NextChildOffset();
+ nsIFrame* prevKidFrame;
+
+ LastChild(prevKidFrame); // XXX remember this...
+
+ for (;;) {
+ // Get the next content object
+ nsIContent* cell = mContent->ChildAt(kidIndex);
+ if (nsnull == cell) {
+ result = frComplete;
+ break;
+ }
+
+ // Make sure we still have room left
+ if (aState.availSize.height <= 0) {
+ // Note: return status was set to frNotComplete above...
+ NS_RELEASE(cell); // cell: REFCNT--(a)
+ break;
+ }
+
+ // Resolve style
+ nsIStyleContext* kidStyleContext =
+ aPresContext->ResolveStyleContextFor(cell, this);
+ nsStyleMolecule* kidMol =
+ (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
+ nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
+ nscoord bottomMargin = kidMol->margin.bottom;
+
+ nsIFrame* kidFrame;
+
+ // Create a child frame
+ if (nsnull == kidPrevInFlow) {
+ nsIContentDelegate* kidDel = nsnull;
+ kidDel = cell->GetDelegate(aPresContext);
+ kidFrame = kidDel->CreateFrame(aPresContext, cell, kidIndex, this);
+ NS_RELEASE(kidDel);
+ kidFrame->SetStyleContext(kidStyleContext);
+ } else {
+ kidPrevInFlow->CreateContinuingFrame(aPresContext, this, kidFrame);
+ }
+ NS_RELEASE(kidStyleContext);
+
+ // Try to reflow the child into the available space. It might not
+ // fit or might need continuing.
+ nsReflowMetrics desiredSize;
+ ReflowStatus status;
+ if (NS_UNCONSTRAINEDSIZE == aState.availSize.width)
+ {
+ // Reflow the child into the available space
+ status = ReflowChild(kidFrame, aPresContext, desiredSize,
+ kidAvailSize, pKidMaxElementSize);
+ nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize);
+ aState.tableFrame->SetCellLayoutData(&kidLayoutData, (nsTableCell *)cell);
+ }
+ else
+ { // we're in a constrained situation, so get the avail width from the known column widths
+ nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell);
+ PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex();
+ PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan();
+ nscoord availWidth = 0;
+ for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
+ NS_ASSERTION(0width, pKidMaxElementSize->height);
+ else
+ printf("reflow of cell returned result = %s with desired=%d,%d, min = nsnull\n",
+ status==frComplete?"complete":"NOT complete",
+ desiredSize.width, desiredSize.height);
+ }
+ }
+ NS_RELEASE(cell); // cell: REFCNT--
+
+ // Did the child fit?
+ if ((desiredSize.height > aState.availSize.height) && (nsnull != mFirstChild)) {
+ // The child is too wide to fit in the available space, and it's
+ // not our first child. Add the frame to our overflow list
+ NS_ASSERTION(nsnull == mOverflowList, "bad overflow list");
+ mOverflowList = kidFrame;
+ prevKidFrame->SetNextSibling(nsnull);
+ break;
+ }
+
+ aState.x = 0;
+ // if we're constrained, compute the x offset where the cell should be put
+ if (NS_UNCONSTRAINEDSIZE!=aState.availSize.width)
+ {
+ // Adjust the running x-offset, taking into account intruders (cells from prior rows with rowspans > 1)
+ PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
+ for (PRInt32 colIndex=0; colIndexGetColumnWidth(colIndex);
+ }
+ // Place the child
+ nsRect kidRect (aState.x, topMargin, desiredSize.width, desiredSize.height);
+ PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize);
+
+ // Link child frame into the list of children
+ if (nsnull != prevKidFrame) {
+ prevKidFrame->SetNextSibling(kidFrame);
+ } else {
+ mFirstChild = kidFrame; // our first child
+ SetFirstContentOffset(kidFrame);
+ }
+ prevKidFrame = kidFrame;
+ mChildCount++;
+ kidIndex++;
+
+ // Did the child complete?
+ if (frNotComplete == status) {
+ // If the child isn't complete then it means that we've used up
+ // all of our available space
+ mLastContentIsComplete = PR_FALSE;
+ break;
+ }
+ kidPrevInFlow = nsnull;
+ }
+
+ SetMaxChildHeight(aState.maxCellHeight); // remember height of tallest child who doesn't have a row span
+
+ // Update the content mapping
+ NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child");
+ SetLastContentOffset(prevKidFrame);
+#ifdef NS_DEBUG
+ PRInt32 len = LengthOf(mFirstChild);
+ NS_ASSERTION(len == mChildCount, "bad child count");
+#endif
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+ return result;
+}
- */
/** Layout the entire row.
* This method stacks rows horizontally according to HTML 4.0 rules.
- * Rows are responsible for layout of their children.
+ * Rows are responsible for layout of their children (cells).
*/
NS_METHOD
nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
@@ -139,176 +933,75 @@ nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
nsSize* aMaxElementSize,
ReflowStatus& aStatus)
{
- if (gsDebug1==PR_TRUE)
- printf("nsTableRowFrame::ResizeReflow - %p with aMaxSize = %d, %d\n",
- this, aMaxSize.width, aMaxSize.height);
+ if (gsDebug1==PR_TRUE)
+ printf("nsTableRowFrame::ResizeReflow - aMaxSize = %d, %d\n",
+ aMaxSize.width, aMaxSize.height);
#ifdef NS_DEBUG
PreReflowCheck();
#endif
- //nsresult result = NS_OK;
- PRInt32 maxCellHeight = 0;
+ // Initialize out parameter
+ if (nsnull != aMaxElementSize) {
+ aMaxElementSize->width = 0;
+ aMaxElementSize->height = 0;
+ }
+
+ // Initialize our internal data
ResetMaxChildHeight();
+ PRBool reflowMappedOK = PR_TRUE;
+
aStatus = frComplete;
- mFirstContentOffset = mLastContentOffset = 0;
+ // Check for an overflow list
+ MoveOverflowToChildList();
- nsSize availSize(aMaxSize);
- nsSize maxSize(0, 0);
- nsSize kidMaxSize(0,0);
- nsSize kidMaxElementSize(0,0);
- nsReflowMetrics kidSize;
- nscoord cellXOffset = 0;
- nscoord maxAscent = 0;
- nscoord maxDescent = 0;
- PRInt32 kidIndex = 0;
- PRInt32 lastIndex = mContent->ChildCount();
- nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
+ nsStyleMolecule* myMol =
+ (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
+ RowReflowState state(aPresContext, aMaxSize, myMol);
+ mContentParent->GetContentParent((nsIFrame*&)(state.tableFrame));
-// Row doesn't factor in insets, the cells do that
-
- nsTableFrame *tableFrame;
-
- mContentParent->GetContentParent((nsIFrame*&)tableFrame);
-
- for (;;) {
- nsTableCell* cell = (nsTableCell *)(mContent->ChildAt(kidIndex)); // cell: REFCNT++
- if (nsnull == cell) {
- aStatus = frComplete;
- break;
+ // Reflow the existing frames
+ if (nsnull != mFirstChild) {
+ reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize);
+ if (PR_FALSE == reflowMappedOK) {
+ aStatus = frNotComplete;
}
-
- // get next frame, creating one if needed
- nsIFrame* kidFrame=nsnull;
- if (nsnull!=prevKidFrame)
- prevKidFrame->GetNextSibling(kidFrame); // no need to check for an error, just see if it returned null...
- else
- ChildAt(0, kidFrame);
- if (nsnull==kidFrame)
- {
- nsIContentDelegate* kidDel;
- kidDel = cell->GetDelegate(aPresContext);
- kidFrame = kidDel->CreateFrame(aPresContext, cell, kidIndex, this);
- mChildCount++;
- NS_RELEASE(kidDel);
- // Resolve style
- nsIStyleContext* kidStyleContext =
- aPresContext->ResolveStyleContextFor(cell, this);
- NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid.");
- kidFrame->SetStyleContext(kidStyleContext);
- NS_RELEASE(kidStyleContext);
- }
-
- // Try to reflow the child into the available space.
- if (NS_UNCONSTRAINEDSIZE == availSize.width)
- { // Each cell is given the entire row width to try to lay out into
- aStatus = ReflowChild(kidFrame, aPresContext, kidSize, availSize, &kidMaxSize);
- if (gsDebug1) printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
- aStatus==frComplete?"complete":"NOT complete",
- kidSize.width, kidSize.height, kidMaxSize.width, kidMaxSize.height);
- nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &kidSize, &kidMaxSize);
- tableFrame->SetCellLayoutData(&kidLayoutData, cell);
- }
- else
- { // we're in a constrained situation, so get the avail width from the known column widths
- nsTableFrame *innerTableFrame;
-
- mContentParent->GetContentParent((nsIFrame*&)innerTableFrame);
- nsCellLayoutData *cellData = innerTableFrame->GetCellLayoutData(cell);
- PRInt32 cellStartingCol = cell->GetColIndex();
- PRInt32 cellColSpan = cell->GetColSpan();
- PRInt32 availWidth = 0;
- for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
- NS_ASSERTION(0GetColIndex(); colIndex++)
- cellXOffset += innerTableFrame->GetColumnWidth(colIndex);
- }
- PRInt32 rowSpan = cell->GetRowSpan();
- if ((1==rowSpan) && (maxCellHeightSetRect(nsRect(cellXOffset, 0, kidSize.width, kidSize.height));
- if (kidSize.width > maxSize.width) {
- maxSize.width = kidSize.width;
- }
- if (NS_UNCONSTRAINEDSIZE==aMaxSize.height)
- {
- if ((1==rowSpan) && (kidSize.height > maxSize.height))
- maxSize.height = kidSize.height;
- if (kidMaxSize.height > kidMaxElementSize.height)
- kidMaxElementSize.height = kidMaxSize.height;
- }
- else
- { // in the constrained height case, our maxElementSize is the height of our tallest cell
- if ((1==rowSpan) && (kidSize.height > maxSize.height))
- maxSize.height = kidSize.height;
- if (maxSize.height > kidMaxElementSize.height)
- kidMaxElementSize.height = maxSize.height;
- }
- kidMaxElementSize.width += kidMaxSize.width;
- if (NS_UNCONSTRAINEDSIZE!=cellXOffset)
- cellXOffset+=kidSize.width;
- if (cellXOffset<=0)
- cellXOffset = NS_UNCONSTRAINEDSIZE; // handle overflow
-
- // Link child frame into the list of children
- if (nsnull != prevKidFrame) {
- prevKidFrame->SetNextSibling(kidFrame);
- } else {
- // Our first child (**blush**)
- if (gsDebug1) printf ("row frame %p, setting first child to %p\n", this, kidFrame);
- mFirstChild = kidFrame;
- SetFirstContentOffset(kidFrame);
- if (gsDebug1) printf("ROW: set first content offset to %d\n", GetFirstContentOffset()); //@@@
- }
- prevKidFrame = kidFrame;
-
- kidIndex++;
- if (frNotComplete == aStatus) {
- // If the child didn't finish layout then it means that it used
- // up all of our available space (or needs us to split).
- mLastContentIsComplete = PR_FALSE;
- break;
- }
- NS_RELEASE(cell); // kid: REFCNT--
}
- if (nsnull != prevKidFrame) {
-#ifdef NS_DEBUG
- if (!IsLastChild(prevKidFrame))
- {
- mGeometricParent->List();
+ // Did we successfully relow our mapped children?
+ if (PR_TRUE == reflowMappedOK) {
+ // Any space left?
+ if (state.availSize.height <= 0) {
+ // No space left. Don't try to pull-up children or reflow unmapped
+ if (NextChildOffset() < mContent->ChildCount()) {
+ aStatus = frNotComplete;
+ }
+ } else if (NextChildOffset() < mContent->ChildCount()) {
+ // Try and pull-up some children from a next-in-flow
+ if (PullUpChildren(aPresContext, state, aMaxElementSize)) {
+ // If we still have unmapped children then create some new frames
+ if (NextChildOffset() < mContent->ChildCount()) {
+ aStatus = ReflowUnmappedChildren(aPresContext, state, aMaxElementSize);
+ }
+ } else {
+ // We were unable to pull-up all the existing frames from the
+ // next in flow
+ aStatus = frNotComplete;
+ }
}
-#endif
- NS_ASSERTION(IsLastChild(prevKidFrame), "unexpected last child");
- SetLastContentOffset(prevKidFrame);
}
- // Return our size and our result
- aDesiredSize.width = cellXOffset;
- aDesiredSize.height = maxSize.height;
- aDesiredSize.ascent = maxAscent;
- aDesiredSize.descent = maxDescent;
- if (nsnull != aMaxElementSize) {
- *aMaxElementSize = kidMaxElementSize;
+ if (frComplete == aStatus) {
+ // Don't forget to add in the bottom margin from our last child.
+ // Only add it in if there's room for it.
+ nscoord margin = state.prevMaxPosBottomMargin -
+ state.prevMaxNegBottomMargin;
}
- SetMaxChildHeight(maxCellHeight); // remember height of tallest child who doesn't have a row span
+
+ // Return our desired rect
+ aDesiredSize.width = aMaxSize.width;
+ aDesiredSize.height = state.maxCellHeight;
#ifdef NS_DEBUG
PostReflowCheck(aStatus);
@@ -326,10 +1019,9 @@ nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
aStatus==frComplete?"Complete":"Not Complete",
aDesiredSize.width, aDesiredSize.height);
}
-
- // testing...
- aStatus = frComplete;
+
return NS_OK;
+
}
NS_METHOD
diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h
index 20446c32384..c10efc5ba8b 100644
--- a/mozilla/layout/html/table/src/nsTableRowFrame.h
+++ b/mozilla/layout/html/table/src/nsTableRowFrame.h
@@ -21,6 +21,8 @@
#include "nscore.h"
#include "nsContainerFrame.h"
+struct RowReflowState;
+
/**
* nsTableRowFrame is the frame that maps table rows
@@ -110,12 +112,60 @@ protected:
/** protected constructor.
* @see NewFrame
*/
- nsTableRowFrame(nsIContent* aContent,
- PRInt32 aIndexInParent,
- nsIFrame* aParentFrame);
+ nsTableRowFrame(nsIContent* aContent,
+ PRInt32 aIndexInParent,
+ nsIFrame* aParentFrame);
+
+ /** destructor */
+ virtual ~nsTableRowFrame();
+
+ nscoord GetTopMarginFor(nsIPresContext* aCX,
+ RowReflowState& aState,
+ nsStyleMolecule* aKidMol);
+
+ void PlaceChild( nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsIFrame* aKidFrame,
+ const nsRect& aKidRect,
+ nsSize* aMaxElementSize,
+ nsSize& aKidMaxElementSize);
+
+ /**
+ * Reflow the frames we've already created
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return true if we successfully reflowed all the mapped children and false
+ * otherwise, e.g. we pushed children to the next in flow
+ */
+ PRBool ReflowMappedChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize);
+
+ /**
+ * Try and pull-up frames from our next-in-flow
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return true if we successfully pulled-up all the children and false
+ * otherwise, e.g. child didn't fit
+ */
+ PRBool PullUpChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize);
+
+ /**
+ * Create new frames for content we haven't yet mapped
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return frComplete if all content has been mapped and frNotComplete
+ * if we should be continued
+ */
+ ReflowStatus ReflowUnmappedChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize);
- /** destructor */
- virtual ~nsTableRowFrame();
private:
PRInt32 mTallestCell; // not my height, but the height of my tallest child
diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp
index 06689af4349..e43975e4609 100644
--- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp
@@ -95,14 +95,24 @@ struct RowGroupReflowState {
/* ----------- nsTableRowGroupFrame ---------- */
nsTableRowGroupFrame::nsTableRowGroupFrame(nsIContent* aContent,
- PRInt32 aIndexInParent,
- nsIFrame* aParentFrame)
+ PRInt32 aIndexInParent,
+ nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aIndexInParent, aParentFrame)
{
+ mType = aContent->GetTag(); // mType: REFCNT++
}
nsTableRowGroupFrame::~nsTableRowGroupFrame()
{
+ if (nsnull!=mType)
+ NS_RELEASE(mType); // mType: REFCNT--
+}
+
+NS_METHOD nsTableRowGroupFrame::GetRowGroupType(nsIAtom *& aType)
+{
+ NS_ADDREF(mType);
+ aType=mType;
+ return NS_OK;
}
@@ -264,6 +274,8 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
nsSize kidAvailSize(aState.availSize);
+ if (0>=kidAvailSize.height)
+ kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet
nsReflowMetrics desiredSize;
nsIFrame::ReflowStatus status;
@@ -290,7 +302,7 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
// Reflow the child into the available space
status = ReflowChild(kidFrame, aPresContext, desiredSize,
- kidAvailSize, pKidMaxElementSize);
+ kidAvailSize, pKidMaxElementSize);
// Did the child fit?
if ((kidFrame != mFirstChild) &&
@@ -381,6 +393,12 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
break;
}
+ // Add back in the left and right margins, because one row does not
+ // impact another row's width
+ if (PR_FALSE == aState.unconstrainedWidth) {
+ kidAvailSize.width += kidMol->margin.left + kidMol->margin.right;
+ }
+
// Get the next child
kidFrame->GetNextSibling(kidFrame);
@@ -868,10 +886,10 @@ nsTableRowGroupFrame::ResizeReflow( nsIPresContext* aPresContext,
}
// Return our desired rect
- NS_ASSERTION(0GetColSpan();
+ }
+ return result;
+}
+
+/** helper method to get the col index of this frame's content (which must be a cell) */
+PRInt32 nsTableCellFrame::GetColIndex()
+{
+ PRInt32 result = 0;
+ nsTableCell *cellContent = (nsTableCell *)mContent;
+ if (nsnull!=cellContent)
+ {
+ result = cellContent->GetColIndex();
+ }
+ return result;
+}
+
void nsTableCellFrame::CreatePsuedoFrame(nsIPresContext* aPresContext)
{
// Do we have a prev-in-flow?
@@ -229,6 +253,8 @@ NS_METHOD nsTableCellFrame::ResizeReflow(nsIPresContext* aPresContext,
// Try to reflow the child into the available space. It might not
// fit or might need continuing.
+ if (availSize.height < 0)
+ availSize.height = 1;
nsSize maxKidElementSize;
if (gsDebug==PR_TRUE)
printf(" nsTableCellFrame::ResizeReflow calling ReflowChild with availSize=%d,%d\n",
diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h
index 3199b6efa5d..65daa2c299a 100644
--- a/mozilla/layout/tables/nsTableCellFrame.h
+++ b/mozilla/layout/tables/nsTableCellFrame.h
@@ -63,8 +63,15 @@ public:
void VerticallyAlignChild(nsIPresContext* aPresContext);
+ /** return the mapped cell's row span. Always >= 1. */
virtual PRInt32 GetRowSpan();
+ /** return the mapped cell's col span. Always >= 1. */
+ virtual PRInt32 GetColSpan();
+
+ /** return the mapped cell's column index (starting at 0 for the first column) */
+ virtual PRInt32 GetColIndex();
+
virtual ~nsTableCellFrame();
protected:
diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp
index e4de2748789..f34bd8818ce 100644
--- a/mozilla/layout/tables/nsTableFrame.cpp
+++ b/mozilla/layout/tables/nsTableFrame.cpp
@@ -90,6 +90,12 @@ struct InnerTableReflowState {
// Flag for whether we're dealing with the first interior row group
PRBool firstRowGroup;
+ // a list of the footers in this table frame, for quick access when inserting bodies
+ nsVoidArray *footerList;
+
+ // cache the total height of the footers for placing body rows
+ nscoord footerHeight;
+
InnerTableReflowState(nsIPresContext* aPresContext,
const nsSize& aMaxSize,
nsStyleMolecule* aMol)
@@ -103,9 +109,13 @@ struct InnerTableReflowState {
unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
firstRowGroup = PR_TRUE;
+ footerHeight = 0;
+ footerList = nsnull;
}
~InnerTableReflowState() {
+ if (nsnull!=footerList)
+ delete footerList;
}
};
@@ -712,7 +722,7 @@ nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresCont
nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
#ifdef NS_DEBUG
- PreReflowCheck();
+ //PreReflowCheck();
#endif
// Initialize out parameter
@@ -775,7 +785,7 @@ nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresCont
}
// Return our desired rect
- NS_ASSERTION(0GetRowGroupType(kidType);
+ if (tFootTag==kidType)
+ {
+ if (nsnull==aState.footerList)
+ aState.footerList = new nsVoidArray();
+ aState.footerList->AppendElement((void *)aKidFrame);
+ aState.footerHeight += aKidRect.height;
+ }
+ // else if this is a body row group, push down all the footer row groups
+ else
+ {
+ // don't bother unless there are footers to push down
+ if (nsnull!=aState.footerList && 0!=aState.footerList->Count())
+ {
+ nsPoint origin;
+ aKidFrame->GetOrigin(origin);
+ origin.y -= aState.footerHeight;
+ aKidFrame->MoveTo(origin.x, origin.y);
+ nsIAtom * tBodyTag = NS_NewAtom(nsTablePart::kRowGroupBodyTagString); // tBodyTag: REFCNT++
+ if (tBodyTag==kidType)
+ {
+ PRInt32 numFooters = aState.footerList->Count();
+ for (PRInt32 footerIndex = 0; footerIndex < numFooters; footerIndex++)
+ {
+ nsTableRowGroupFrame * footer = (nsTableRowGroupFrame *)(aState.footerList->ElementAt(footerIndex));
+ NS_ASSERTION(nsnull!=footer, "bad footer list in table inner frame.");
+ if (nsnull!=footer)
+ {
+ footer->GetOrigin(origin);
+ origin.y += aKidRect.height;
+ footer->MoveTo(origin.x, origin.y);
+ }
+ }
+ }
+ NS_RELEASE(tBodyTag);
+ }
+ }
+ NS_RELEASE(tFootTag);
+
// Update the maximum element size
if (PR_TRUE==aState.firstRowGroup)
{
@@ -1284,8 +1336,8 @@ PRBool nsTableFrame::PullUpChildren(nsIPresContext* aPresContext,
*/
nsIFrame::ReflowStatus
nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext,
- InnerTableReflowState& aState,
- nsSize* aMaxElementSize)
+ InnerTableReflowState& aState,
+ nsSize* aMaxElementSize)
{
#ifdef NS_DEBUG
VerifyLastIsComplete();
@@ -2441,16 +2493,53 @@ NS_METHOD nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
cf->SetRect(nsRect(0, 0, mRect.width, 0));
// add headers and footers to cf
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
- PRInt32 childCount;
-
- firstInFlow->ChildCount(childCount);
- PRInt32 childIndex = 0;
- for (; childIndex < childCount; childIndex++)
+ nsIFrame * rg = nsnull;
+ firstInFlow->ChildAt(0, rg);
+ NS_ASSERTION (nsnull!=rg, "previous frame has no children");
+ nsIAtom * tHeadTag = NS_NewAtom(nsTablePart::kRowGroupHeadTagString); // tHeadTag: REFCNT++
+ nsIAtom * tFootTag = NS_NewAtom(nsTablePart::kRowGroupFootTagString); // tFootTag: REFCNT++
+ PRInt32 index = 0;
+ nsIFrame * bodyRowGroupFromOverflow = mOverflowList;
+ nsIFrame * lastSib = nsnull;
+ for ( ; nsnull!=rg; index++)
{
- // TODO: place copies of the header and footer row groups here
- // maybe need to do this in ResizeReflow at the beginning, when we determine we are a continuing frame
+ nsIContent *content = nsnull;
+ rg->GetContent(content); // content: REFCNT++
+ NS_ASSERTION(nsnull!=content, "bad frame, returned null content.");
+ nsIAtom * rgTag = content->GetTag();
+ // if we've found a header or a footer, replicate it
+ if (tHeadTag==rgTag || tFootTag==rgTag)
+ {
+ printf("found a head or foot in continuing frame\n");
+ // Resolve style for the child
+ nsIStyleContext* kidStyleContext =
+ aPresContext->ResolveStyleContextFor(content, cf); // kidStyleContext: REFCNT++
+ nsStyleMolecule* kidMol =
+ (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
+ nsIContentDelegate* kidDel = nsnull;
+ kidDel = content->GetDelegate(aPresContext); // kidDel: REFCNT++
+ nsIFrame * duplicateFrame = kidDel->CreateFrame(aPresContext, content, index, cf);
+ NS_RELEASE(kidDel); // kidDel: REFCNT--
+ duplicateFrame->SetStyleContext(kidStyleContext);
+ NS_RELEASE(kidStyleContext); // kidStyleContenxt: REFCNT--
+
+ if (nsnull==lastSib)
+ {
+ mOverflowList = duplicateFrame;
+ }
+ else
+ {
+ lastSib->SetNextSibling(duplicateFrame);
+ }
+ duplicateFrame->SetNextSibling(bodyRowGroupFromOverflow);
+ lastSib = duplicateFrame;
+ }
+ NS_RELEASE(content); // content: REFCNT--
+ // get the next row group
+ rg->GetNextSibling(rg);
}
-
+ NS_RELEASE(tFootTag); // tHeadTag: REFCNT --
+ NS_RELEASE(tHeadTag); // tFootTag: REFCNT --
aContinuingFrame = cf;
return NS_OK;
}
diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp
index 2439865157f..a33de28ae1f 100644
--- a/mozilla/layout/tables/nsTableOuterFrame.cpp
+++ b/mozilla/layout/tables/nsTableOuterFrame.cpp
@@ -305,7 +305,13 @@ NS_METHOD nsTableOuterFrame::ResizeReflow(nsIPresContext* aPresContext,
//NS_ASSERTION(0 aState.availSize.height) && (kidFrame != mFirstChild)) {
- // The child is too wide to fit in the available space, and it's
+ // The child is too tall to fit in the available space, and it's
// not our first child
// Since we are giving the next-in-flow our last child, we
@@ -518,8 +524,6 @@ PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContex
// Update mLastContentIsComplete now that this kid fits
mLastContentIsComplete = PRBool(status == frComplete);
- // Is the child complete?
- mLastContentIsComplete = PRBool(status == frComplete);
if (frNotComplete == status) {
// No, the child isn't complete
nsIFrame* kidNextInFlow;
@@ -555,6 +559,21 @@ PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContex
kidFrame->GetNextSibling(nextSibling);
if (nsnull != nextSibling) {
PushChildren(nextSibling, kidFrame, lastContentIsComplete);
+ /* debug */
+ /*
+ printf ("having just pushed children, here is the frame hierarchy.\n");
+ nsIFrame *p;
+ GetGeometricParent(p);
+ nsIFrame *root;
+ while (nsnull!=p)
+ {
+ root = p;
+ p->GetGeometricParent(p);
+ }
+ root->List();
+ fflush(stdout);
+ */
+ /* end debug */
SetLastContentOffset(prevKidFrame);
}
result = PR_FALSE;
diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp
index 2af64ea1fb8..318e92d5cbb 100644
--- a/mozilla/layout/tables/nsTableRowFrame.cpp
+++ b/mozilla/layout/tables/nsTableRowFrame.cpp
@@ -40,9 +40,61 @@ static const PRBool gsDebug2 = PR_FALSE;
static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
+/* ----------- RowReflowState ---------- */
+
+struct RowReflowState {
+
+ // The body's style molecule
+ nsStyleMolecule* mol;
+
+ // The body's available size (computed from the body's parent)
+ nsSize availSize;
+
+ // Margin tracking information
+ nscoord prevMaxPosBottomMargin;
+ nscoord prevMaxNegBottomMargin;
+
+ // Flags for whether the max size is unconstrained
+ PRBool unconstrainedWidth;
+ PRBool unconstrainedHeight;
+
+ // Running x-offset
+ nscoord x;
+
+ // Height of tallest cell (excluding cells with rowspan>1)
+ nscoord maxCellHeight;
+
+ nsTableFrame *tableFrame;
+
+
+ RowReflowState( nsIPresContext* aPresContext,
+ const nsSize& aMaxSize,
+ nsStyleMolecule* aMol)
+ {
+ mol = aMol;
+ availSize.width = aMaxSize.width;
+ availSize.height = aMaxSize.height;
+ prevMaxPosBottomMargin = 0;
+ prevMaxNegBottomMargin = 0;
+ x=0;
+ unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
+ unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
+ maxCellHeight=0;
+ tableFrame = nsnull;
+ }
+
+ ~RowReflowState() {
+ }
+};
+
+
+
+
+/* ----------- nsTableRowpFrame ---------- */
+
nsTableRowFrame::nsTableRowFrame(nsIContent* aContent,
- PRInt32 aIndexInParent,
- nsIFrame* aParentFrame)
+ PRInt32 aIndexInParent,
+ nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aIndexInParent, aParentFrame),
mTallestCell(0)
{
@@ -120,17 +172,759 @@ PRInt32 nsTableRowFrame::GetTallestChild() const
return mTallestCell;
}
-/*
+// Collapse child's top margin with previous bottom margin
+nscoord nsTableRowFrame::GetTopMarginFor( nsIPresContext* aCX,
+ RowReflowState& aState,
+ nsStyleMolecule* aKidMol)
+{
+ nscoord margin;
+ nscoord maxNegTopMargin = 0;
+ nscoord maxPosTopMargin = 0;
+ if ((margin = aKidMol->margin.top) < 0) {
+ maxNegTopMargin = -margin;
+ } else {
+ maxPosTopMargin = margin;
+ }
-want to use min space the child can fit in to
-determine its real size, unless fixed columns sizes
-are present.
+ nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin);
+ nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin);
+ margin = maxPos - maxNeg;
+
+ return margin;
+}
+
+// Position and size aKidFrame and update our reflow state. The origin of
+// aKidRect is relative to the upper-left origin of our frame, and includes
+// any left/top margin.
+void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsIFrame* aKidFrame,
+ const nsRect& aKidRect,
+ nsSize* aMaxElementSize,
+ nsSize& aKidMaxElementSize)
+{
+ if (PR_TRUE==gsDebug1)
+ printf ("row: placing cell at %d, %d, %d, %d\n",
+ aKidRect.x, aKidRect.y, aKidRect.width, aKidRect.height);
+
+ // Place and size the child
+ aKidFrame->SetRect(aKidRect);
+
+ // Update the maximum element size
+ PRInt32 rowSpan = ((nsTableCellFrame*)aKidFrame)->GetRowSpan();
+ if (nsnull != aMaxElementSize) {
+ aMaxElementSize->width += aKidMaxElementSize.width;
+ if ((1==rowSpan) && (aKidMaxElementSize.height>aMaxElementSize->height))
+ {
+ aMaxElementSize->height = aKidMaxElementSize.height;
+ }
+ }
+ if ((1==rowSpan) && (aState.maxCellHeightmFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ NS_PRECONDITION(nsnull != mFirstChild, "no children");
+
+ PRInt32 childCount = 0;
+ nsIFrame* prevKidFrame = nsnull;
+
+ // Remember our original mLastContentIsComplete so that if we end up
+ // having to push children, we have the correct value to hand to
+ // PushChildren.
+ PRBool lastContentIsComplete = mLastContentIsComplete;
+
+ nsSize kidMaxElementSize;
+ nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
+ PRBool result = PR_TRUE;
+
+ for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
+ nsIContent* cell = nsnull;
+ kidFrame->GetContent(cell); // cell: REFCNT++
+ nsSize kidAvailSize(aState.availSize);
+ if (0>=kidAvailSize.height)
+ kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet
+ nsReflowMetrics desiredSize;
+ nsIFrame::ReflowStatus status;
+
+ // Get top margin for this kid
+ nsIStyleContext* kidSC;
+ kidFrame->GetStyleContext(aPresContext, kidSC);
+ nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+ nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
+ nscoord bottomMargin = kidMol->margin.bottom;
+ NS_RELEASE(kidSC);
+
+ // Figure out the amount of available size for the child (subtract
+ // off the top margin we are going to apply to it)
+ if (PR_FALSE == aState.unconstrainedHeight) {
+ kidAvailSize.height -= topMargin;
+ }
+ // Subtract off for left and right margin
+ if (PR_FALSE == aState.unconstrainedWidth) {
+ kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
+ }
+
+ if (NS_UNCONSTRAINEDSIZE == aState.availSize.width)
+ {
+ // Reflow the child into the available space
+ status = ReflowChild(kidFrame, aPresContext, desiredSize,
+ kidAvailSize, pKidMaxElementSize);
+ nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize);
+ aState.tableFrame->SetCellLayoutData(&kidLayoutData, (nsTableCell *)cell);
+ }
+ else
+ { // we're in a constrained situation, so get the avail width from the known column widths
+ nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell);
+ PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex();
+ PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan();
+ nscoord availWidth = 0;
+ for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
+ NS_ASSERTION(0width, pKidMaxElementSize->height);
+ else
+ printf("reflow of cell returned result = %s with desired=%d,%d, min = nsnull\n",
+ status==frComplete?"complete":"NOT complete",
+ desiredSize.width, desiredSize.height);
+ }
+ }
+ NS_RELEASE(cell); // cell: REFCNT--
+ // Did the child fit?
+ if ((kidFrame != mFirstChild) &&
+ ((kidAvailSize.height <= 0) ||
+ (desiredSize.height > kidAvailSize.height)))
+ {
+ // The child's height is too big to fit at all in our remaining space,
+ // and it's not our first child.
+
+ // Since we are giving the next-in-flow our last child, we
+ // give it our original mLastContentIsComplete, too (in case we
+ // are pushing into an empty next-in-flow)
+ PushChildren(kidFrame, prevKidFrame, lastContentIsComplete);
+ SetLastContentOffset(prevKidFrame);
+
+ // Our mLastContentIsComplete was already set by the last kid we
+ // reflowed reflow's status
+ result = PR_FALSE;
+ break;
+ }
+
+ // Adjust the running x-offset, taking into account intruders (cells from prior rows with rowspans > 1)
+ aState.x = 0;
+ PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
+ for (PRInt32 colIndex=0; colIndexGetColumnWidth(colIndex);
+ // Place the child after taking into account it's margin
+ nsRect kidRect (aState.x, topMargin, desiredSize.width, desiredSize.height);
+ PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize,
+ kidMaxElementSize);
+ if (bottomMargin < 0) {
+ aState.prevMaxNegBottomMargin = -bottomMargin;
+ } else {
+ aState.prevMaxPosBottomMargin = bottomMargin;
+ }
+ childCount++;
+
+ // Remember where we just were in case we end up pushing children
+ prevKidFrame = kidFrame;
+
+ // Update mLastContentIsComplete now that this kid fits
+ mLastContentIsComplete = PRBool(status == frComplete);
+
+ /* Rows should not create continuing frames for cells
+ * unless they absolutely have to!
+ * check to see if this is absolutely necessary (with new params from troy)
+ * otherwise PushChildren and bail.
+ */
+ // Special handling for incomplete children
+ if (frNotComplete == status) {
+ // XXX It's good to assume that we might still have room
+ // even if the child didn't complete (floaters will want this)
+ nsIFrame* kidNextInFlow;
+
+ kidFrame->GetNextInFlow(kidNextInFlow);
+ PRBool lastContentIsComplete = mLastContentIsComplete;
+ if (nsnull == kidNextInFlow) {
+ // No the child isn't complete, and it doesn't have a next in flow so
+ // create a continuing frame. This hooks the child into the flow.
+ nsIFrame* continuingFrame;
+
+ kidFrame->CreateContinuingFrame(aPresContext, this, continuingFrame);
+
+ // Insert the frame. We'll reflow it next pass through the loop
+ nsIFrame* nextSib;
+
+ kidFrame->GetNextSibling(nextSib);
+ continuingFrame->SetNextSibling(nextSib);
+ kidFrame->SetNextSibling(continuingFrame);
+ if (nsnull == nextSib) {
+ // Assume that the continuation frame we just created is
+ // complete, for now. It will get reflowed by our
+ // next-in-flow (we are going to push it now)
+ lastContentIsComplete = PR_TRUE;
+ }
+ }
+ // We've used up all of our available space so push the remaining
+ // children to the next-in-flow
+ nsIFrame* nextSibling;
+
+ kidFrame->GetNextSibling(nextSibling);
+ if (nsnull != nextSibling) {
+ PushChildren(nextSibling, kidFrame, lastContentIsComplete);
+ SetLastContentOffset(prevKidFrame);
+ }
+ result = PR_FALSE;
+ break;
+ }
+
+ // Add back in the left and right margins, because one row does not
+ // impact another row's width
+ if (PR_FALSE == aState.unconstrainedWidth) {
+ kidAvailSize.width += kidMol->margin.left + kidMol->margin.right;
+ }
+
+ // Get the next child
+ kidFrame->GetNextSibling(kidFrame);
+
+ }
+
+ SetMaxChildHeight(aState.maxCellHeight); // remember height of tallest child who doesn't have a row span
+
+ // Update the child count
+ mChildCount = childCount;
+
+#ifdef NS_DEBUG
+ NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count");
+
+ nsIFrame* lastChild;
+ PRInt32 lastIndexInParent;
+
+ LastChild(lastChild);
+ lastChild->GetIndexInParent(lastIndexInParent);
+ NS_POSTCONDITION(lastIndexInParent == mLastContentOffset, "bad last content offset");
+#endif
+
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+ ListTag(stdout);
+ printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n",
+ (result ? "" : "NOT "),
+ mChildCount,
+ mFirstContentOffset, mLastContentOffset,
+ (mLastContentIsComplete ? 'T' : 'F'));
+#ifdef NOISY_FLOW
+ {
+ nsTableRowFrame* flow = (nsTableRowFrame*) mNextInFlow;
+ while (flow != 0) {
+ printf(" %p: [%d,%d,%c]\n",
+ flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ return result;
+}
+
+/**
+ * Try and pull-up frames from our next-in-flow
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return true if we successfully pulled-up all the children and false
+ * otherwise, e.g. child didn't fit
+ */
+PRBool nsTableRowFrame::PullUpChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize)
+{
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+ ListTag(stdout);
+ printf(": pullup (childCount=%d) [%d,%d,%c]\n",
+ mChildCount,
+ mFirstContentOffset, mLastContentOffset,
+ (mLastContentIsComplete ? 'T' : 'F'));
+#ifdef NOISY_FLOW
+ {
+ nsTableRowFrame* flow = (nsTableRowFrame*) mNextInFlow;
+ while (flow != 0) {
+ printf(" %p: [%d,%d,%c]\n",
+ flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ nsTableRowFrame* nextInFlow = (nsTableRowFrame*)mNextInFlow;
+ nsSize kidMaxElementSize;
+ nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
+ nsSize kidAvailSize(aState.availSize);
+#ifdef NS_DEBUG
+ PRInt32 kidIndex = NextChildOffset();
+#endif
+ nsIFrame* prevKidFrame;
+
+ LastChild(prevKidFrame);
+
+ // This will hold the prevKidFrame's mLastContentIsComplete
+ // status. If we have to push the frame that follows prevKidFrame
+ // then this will become our mLastContentIsComplete state. Since
+ // prevKidFrame is initially our last frame, it's completion status
+ // is our mLastContentIsComplete value.
+ PRBool prevLastContentIsComplete = mLastContentIsComplete;
+
+ PRBool result = PR_TRUE;
+
+ while (nsnull != nextInFlow) {
+ nsReflowMetrics desiredSize;
+ ReflowStatus status;
+
+ // Get the next child
+ nsIFrame* kidFrame = nextInFlow->mFirstChild;
+
+ // Any more child frames?
+ if (nsnull == kidFrame) {
+ // No. Any frames on its overflow list?
+ if (nsnull != nextInFlow->mOverflowList) {
+ // Move the overflow list to become the child list
+// NS_ABORT();
+ nextInFlow->AppendChildren(nextInFlow->mOverflowList);
+ nextInFlow->mOverflowList = nsnull;
+ kidFrame = nextInFlow->mFirstChild;
+ } else {
+ // We've pulled up all the children, so move to the next-in-flow.
+ nextInFlow->GetNextInFlow((nsIFrame*&)nextInFlow);
+ continue;
+ }
+ }
+
+ // See if the child fits in the available space. If it fits or
+ // it's splittable then reflow it. The reason we can't just move
+ // it is that we still need ascent/descent information
+ nsSize kidFrameSize;
+ SplittableType kidIsSplittable;
+
+ kidFrame->GetSize(kidFrameSize);
+ kidFrame->IsSplittable(kidIsSplittable);
+
+ if ((kidFrameSize.height > aState.availSize.height) &&
+ (kidIsSplittable == frNotSplittable)) {
+ result = PR_FALSE;
+ mLastContentIsComplete = prevLastContentIsComplete;
+ break;
+ }
+
+ nsIContent *cell = nsnull;
+ kidFrame->GetContent(cell); // cell: REFNCT++
+ // we're in a constrained situation, so get the avail width from the known column widths
+ nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell);
+ PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex();
+ PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan();
+ nscoord availWidth = 0;
+ for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
+ NS_ASSERTION(0width, pKidMaxElementSize->height);
+ else
+ printf("reflow of cell returned result = %s with desired=%d,%d, min = nsnull\n",
+ status==frComplete?"complete":"NOT complete",
+ desiredSize.width, desiredSize.height);
+ }
+ }
+ NS_RELEASE(cell); // cell: REFCNT--
+
+ // Did the child fit?
+ if ((desiredSize.height > aState.availSize.height) && (nsnull != mFirstChild)) {
+ // The child is too tall to fit in the available space, and it's
+ // not our first child
+ result = PR_FALSE;
+ mLastContentIsComplete = prevLastContentIsComplete;
+ break;
+ }
+
+ // Adjust the running x-offset, taking into account intruders (cells from prior rows with rowspans > 1)
+ aState.x = 0;
+ PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
+ for (PRInt32 colIndex=0; colIndexGetColumnWidth(colIndex);
+ // Place the child
+ //nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
+ nsRect kidRect (aState.x, 0, desiredSize.width, desiredSize.height);
+ PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize);
+
+ // Remove the frame from its current parent
+ kidFrame->GetNextSibling(nextInFlow->mFirstChild);
+ nextInFlow->mChildCount--;
+ // Update the next-in-flows first content offset
+ if (nsnull != nextInFlow->mFirstChild) {
+ nextInFlow->SetFirstContentOffset(nextInFlow->mFirstChild);
+ }
+
+ // Link the frame into our list of children
+ kidFrame->SetGeometricParent(this);
+ nsIFrame* kidContentParent;
+
+ kidFrame->GetContentParent(kidContentParent);
+ if (nextInFlow == kidContentParent) {
+ kidFrame->SetContentParent(this);
+ }
+ if (nsnull == prevKidFrame) {
+ mFirstChild = kidFrame;
+ SetFirstContentOffset(kidFrame);
+ } else {
+ prevKidFrame->SetNextSibling(kidFrame);
+ }
+ kidFrame->SetNextSibling(nsnull);
+ mChildCount++;
+
+ // Remember where we just were in case we end up pushing children
+ prevKidFrame = kidFrame;
+ prevLastContentIsComplete = mLastContentIsComplete;
+
+ // Is the child we just pulled up complete?
+ mLastContentIsComplete = PRBool(status == frComplete);
+ if (frNotComplete == status) {
+ // No the child isn't complete
+ nsIFrame* kidNextInFlow;
+
+ kidFrame->GetNextInFlow(kidNextInFlow);
+ if (nsnull == kidNextInFlow) {
+ // The child doesn't have a next-in-flow so create a
+ // continuing frame. The creation appends it to the flow and
+ // prepares it for reflow.
+ nsIFrame* continuingFrame;
+
+ kidFrame->CreateContinuingFrame(aPresContext, this, continuingFrame);
+ NS_ASSERTION(nsnull != continuingFrame, "frame creation failed");
+
+ // Add the continuing frame to our sibling list and then push
+ // it to the next-in-flow. This ensures the next-in-flow's
+ // content offsets and child count are set properly. Note that
+ // we can safely assume that the continuation is complete so
+ // we pass PR_TRUE into PushChidren in case our next-in-flow
+ // was just drained and now needs to know it's
+ // mLastContentIsComplete state.
+ kidFrame->SetNextSibling(continuingFrame);
+
+ PushChildren(continuingFrame, kidFrame, PR_TRUE);
+
+ // After we push the continuation frame we don't need to fuss
+ // with mLastContentIsComplete beause the continuation frame
+ // is no longer on *our* list.
+ }
+
+ // If the child isn't complete then it means that we've used up
+ // all of our available space.
+ result = PR_FALSE;
+ break;
+ }
+ }
+
+ // Update our last content offset
+ if (nsnull != prevKidFrame) {
+ NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child");
+ SetLastContentOffset(prevKidFrame);
+ }
+
+ // We need to make sure the first content offset is correct for any empty
+ // next-in-flow frames (frames where we pulled up all the child frames)
+ nextInFlow = (nsTableRowFrame*)mNextInFlow;
+ if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) {
+ // We have at least one empty frame. Did we succesfully pull up all the
+ // child frames?
+ if (PR_FALSE == result) {
+ // No, so we need to adjust the first content offset of all the empty
+ // frames
+ AdjustOffsetOfEmptyNextInFlows();
+#ifdef NS_DEBUG
+ } else {
+ // Yes, we successfully pulled up all the child frames which means all
+ // the next-in-flows must be empty. Do a sanity check
+ while (nsnull != nextInFlow) {
+ NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow");
+ nextInFlow->GetNextInFlow((nsIFrame*&)nextInFlow);
+ }
+#endif
+ }
+ }
+
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+
+#ifdef NOISY
+ ListTag(stdout);
+ printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n",
+ (result ? "" : "NOT "),
+ mChildCount,
+ mFirstContentOffset, mLastContentOffset,
+ (mLastContentIsComplete ? 'T' : 'F'));
+#ifdef NOISY_FLOW
+ {
+ nsTableRowFrame* flow = (nsTableRowFrame*) mNextInFlow;
+ while (flow != 0) {
+ printf(" %p: [%d,%d,%c]\n",
+ flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+ (flow->mLastContentIsComplete ? 'T' : 'F'));
+ flow = (nsTableRowFrame*) flow->mNextInFlow;
+ }
+ }
+#endif
+#endif
+ return result;
+}
+
+/**
+ * Create new frames for content we haven't yet mapped
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return frComplete if all content has been mapped and frNotComplete
+ * if we should be continued
+ */
+nsIFrame::ReflowStatus
+nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize)
+{
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+ nsIFrame* kidPrevInFlow = nsnull;
+ ReflowStatus result = frNotComplete;
+
+ // If we have no children and we have a prev-in-flow then we need to pick
+ // up where it left off. If we have children, e.g. we're being resized, then
+ // our content offset should already be set correctly...
+ if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) {
+ nsTableRowFrame* prev = (nsTableRowFrame*)mPrevInFlow;
+ NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow");
+
+ mFirstContentOffset = prev->NextChildOffset();
+ if (!prev->mLastContentIsComplete) {
+ // Our prev-in-flow's last child is not complete
+ prev->LastChild(kidPrevInFlow);
+ }
+ }
+
+ mLastContentIsComplete = PR_TRUE;
+
+ // Place our children, one at a time, until we are out of children
+ nsSize kidMaxElementSize;
+ nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
+ nsSize kidAvailSize(aState.availSize);
+ PRInt32 kidIndex = NextChildOffset();
+ nsIFrame* prevKidFrame;
+
+ LastChild(prevKidFrame); // XXX remember this...
+
+ for (;;) {
+ // Get the next content object
+ nsIContent* cell = mContent->ChildAt(kidIndex);
+ if (nsnull == cell) {
+ result = frComplete;
+ break;
+ }
+
+ // Make sure we still have room left
+ if (aState.availSize.height <= 0) {
+ // Note: return status was set to frNotComplete above...
+ NS_RELEASE(cell); // cell: REFCNT--(a)
+ break;
+ }
+
+ // Resolve style
+ nsIStyleContext* kidStyleContext =
+ aPresContext->ResolveStyleContextFor(cell, this);
+ nsStyleMolecule* kidMol =
+ (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
+ nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
+ nscoord bottomMargin = kidMol->margin.bottom;
+
+ nsIFrame* kidFrame;
+
+ // Create a child frame
+ if (nsnull == kidPrevInFlow) {
+ nsIContentDelegate* kidDel = nsnull;
+ kidDel = cell->GetDelegate(aPresContext);
+ kidFrame = kidDel->CreateFrame(aPresContext, cell, kidIndex, this);
+ NS_RELEASE(kidDel);
+ kidFrame->SetStyleContext(kidStyleContext);
+ } else {
+ kidPrevInFlow->CreateContinuingFrame(aPresContext, this, kidFrame);
+ }
+ NS_RELEASE(kidStyleContext);
+
+ // Try to reflow the child into the available space. It might not
+ // fit or might need continuing.
+ nsReflowMetrics desiredSize;
+ ReflowStatus status;
+ if (NS_UNCONSTRAINEDSIZE == aState.availSize.width)
+ {
+ // Reflow the child into the available space
+ status = ReflowChild(kidFrame, aPresContext, desiredSize,
+ kidAvailSize, pKidMaxElementSize);
+ nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize);
+ aState.tableFrame->SetCellLayoutData(&kidLayoutData, (nsTableCell *)cell);
+ }
+ else
+ { // we're in a constrained situation, so get the avail width from the known column widths
+ nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell);
+ PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex();
+ PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan();
+ nscoord availWidth = 0;
+ for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
+ NS_ASSERTION(0width, pKidMaxElementSize->height);
+ else
+ printf("reflow of cell returned result = %s with desired=%d,%d, min = nsnull\n",
+ status==frComplete?"complete":"NOT complete",
+ desiredSize.width, desiredSize.height);
+ }
+ }
+ NS_RELEASE(cell); // cell: REFCNT--
+
+ // Did the child fit?
+ if ((desiredSize.height > aState.availSize.height) && (nsnull != mFirstChild)) {
+ // The child is too wide to fit in the available space, and it's
+ // not our first child. Add the frame to our overflow list
+ NS_ASSERTION(nsnull == mOverflowList, "bad overflow list");
+ mOverflowList = kidFrame;
+ prevKidFrame->SetNextSibling(nsnull);
+ break;
+ }
+
+ aState.x = 0;
+ // if we're constrained, compute the x offset where the cell should be put
+ if (NS_UNCONSTRAINEDSIZE!=aState.availSize.width)
+ {
+ // Adjust the running x-offset, taking into account intruders (cells from prior rows with rowspans > 1)
+ PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
+ for (PRInt32 colIndex=0; colIndexGetColumnWidth(colIndex);
+ }
+ // Place the child
+ nsRect kidRect (aState.x, topMargin, desiredSize.width, desiredSize.height);
+ PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize);
+
+ // Link child frame into the list of children
+ if (nsnull != prevKidFrame) {
+ prevKidFrame->SetNextSibling(kidFrame);
+ } else {
+ mFirstChild = kidFrame; // our first child
+ SetFirstContentOffset(kidFrame);
+ }
+ prevKidFrame = kidFrame;
+ mChildCount++;
+ kidIndex++;
+
+ // Did the child complete?
+ if (frNotComplete == status) {
+ // If the child isn't complete then it means that we've used up
+ // all of our available space
+ mLastContentIsComplete = PR_FALSE;
+ break;
+ }
+ kidPrevInFlow = nsnull;
+ }
+
+ SetMaxChildHeight(aState.maxCellHeight); // remember height of tallest child who doesn't have a row span
+
+ // Update the content mapping
+ NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child");
+ SetLastContentOffset(prevKidFrame);
+#ifdef NS_DEBUG
+ PRInt32 len = LengthOf(mFirstChild);
+ NS_ASSERTION(len == mChildCount, "bad child count");
+#endif
+#ifdef NS_DEBUG
+ VerifyLastIsComplete();
+#endif
+ return result;
+}
- */
/** Layout the entire row.
* This method stacks rows horizontally according to HTML 4.0 rules.
- * Rows are responsible for layout of their children.
+ * Rows are responsible for layout of their children (cells).
*/
NS_METHOD
nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
@@ -139,176 +933,75 @@ nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
nsSize* aMaxElementSize,
ReflowStatus& aStatus)
{
- if (gsDebug1==PR_TRUE)
- printf("nsTableRowFrame::ResizeReflow - %p with aMaxSize = %d, %d\n",
- this, aMaxSize.width, aMaxSize.height);
+ if (gsDebug1==PR_TRUE)
+ printf("nsTableRowFrame::ResizeReflow - aMaxSize = %d, %d\n",
+ aMaxSize.width, aMaxSize.height);
#ifdef NS_DEBUG
PreReflowCheck();
#endif
- //nsresult result = NS_OK;
- PRInt32 maxCellHeight = 0;
+ // Initialize out parameter
+ if (nsnull != aMaxElementSize) {
+ aMaxElementSize->width = 0;
+ aMaxElementSize->height = 0;
+ }
+
+ // Initialize our internal data
ResetMaxChildHeight();
+ PRBool reflowMappedOK = PR_TRUE;
+
aStatus = frComplete;
- mFirstContentOffset = mLastContentOffset = 0;
+ // Check for an overflow list
+ MoveOverflowToChildList();
- nsSize availSize(aMaxSize);
- nsSize maxSize(0, 0);
- nsSize kidMaxSize(0,0);
- nsSize kidMaxElementSize(0,0);
- nsReflowMetrics kidSize;
- nscoord cellXOffset = 0;
- nscoord maxAscent = 0;
- nscoord maxDescent = 0;
- PRInt32 kidIndex = 0;
- PRInt32 lastIndex = mContent->ChildCount();
- nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
+ nsStyleMolecule* myMol =
+ (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
+ RowReflowState state(aPresContext, aMaxSize, myMol);
+ mContentParent->GetContentParent((nsIFrame*&)(state.tableFrame));
-// Row doesn't factor in insets, the cells do that
-
- nsTableFrame *tableFrame;
-
- mContentParent->GetContentParent((nsIFrame*&)tableFrame);
-
- for (;;) {
- nsTableCell* cell = (nsTableCell *)(mContent->ChildAt(kidIndex)); // cell: REFCNT++
- if (nsnull == cell) {
- aStatus = frComplete;
- break;
+ // Reflow the existing frames
+ if (nsnull != mFirstChild) {
+ reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize);
+ if (PR_FALSE == reflowMappedOK) {
+ aStatus = frNotComplete;
}
-
- // get next frame, creating one if needed
- nsIFrame* kidFrame=nsnull;
- if (nsnull!=prevKidFrame)
- prevKidFrame->GetNextSibling(kidFrame); // no need to check for an error, just see if it returned null...
- else
- ChildAt(0, kidFrame);
- if (nsnull==kidFrame)
- {
- nsIContentDelegate* kidDel;
- kidDel = cell->GetDelegate(aPresContext);
- kidFrame = kidDel->CreateFrame(aPresContext, cell, kidIndex, this);
- mChildCount++;
- NS_RELEASE(kidDel);
- // Resolve style
- nsIStyleContext* kidStyleContext =
- aPresContext->ResolveStyleContextFor(cell, this);
- NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid.");
- kidFrame->SetStyleContext(kidStyleContext);
- NS_RELEASE(kidStyleContext);
- }
-
- // Try to reflow the child into the available space.
- if (NS_UNCONSTRAINEDSIZE == availSize.width)
- { // Each cell is given the entire row width to try to lay out into
- aStatus = ReflowChild(kidFrame, aPresContext, kidSize, availSize, &kidMaxSize);
- if (gsDebug1) printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
- aStatus==frComplete?"complete":"NOT complete",
- kidSize.width, kidSize.height, kidMaxSize.width, kidMaxSize.height);
- nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &kidSize, &kidMaxSize);
- tableFrame->SetCellLayoutData(&kidLayoutData, cell);
- }
- else
- { // we're in a constrained situation, so get the avail width from the known column widths
- nsTableFrame *innerTableFrame;
-
- mContentParent->GetContentParent((nsIFrame*&)innerTableFrame);
- nsCellLayoutData *cellData = innerTableFrame->GetCellLayoutData(cell);
- PRInt32 cellStartingCol = cell->GetColIndex();
- PRInt32 cellColSpan = cell->GetColSpan();
- PRInt32 availWidth = 0;
- for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
- NS_ASSERTION(0GetColIndex(); colIndex++)
- cellXOffset += innerTableFrame->GetColumnWidth(colIndex);
- }
- PRInt32 rowSpan = cell->GetRowSpan();
- if ((1==rowSpan) && (maxCellHeightSetRect(nsRect(cellXOffset, 0, kidSize.width, kidSize.height));
- if (kidSize.width > maxSize.width) {
- maxSize.width = kidSize.width;
- }
- if (NS_UNCONSTRAINEDSIZE==aMaxSize.height)
- {
- if ((1==rowSpan) && (kidSize.height > maxSize.height))
- maxSize.height = kidSize.height;
- if (kidMaxSize.height > kidMaxElementSize.height)
- kidMaxElementSize.height = kidMaxSize.height;
- }
- else
- { // in the constrained height case, our maxElementSize is the height of our tallest cell
- if ((1==rowSpan) && (kidSize.height > maxSize.height))
- maxSize.height = kidSize.height;
- if (maxSize.height > kidMaxElementSize.height)
- kidMaxElementSize.height = maxSize.height;
- }
- kidMaxElementSize.width += kidMaxSize.width;
- if (NS_UNCONSTRAINEDSIZE!=cellXOffset)
- cellXOffset+=kidSize.width;
- if (cellXOffset<=0)
- cellXOffset = NS_UNCONSTRAINEDSIZE; // handle overflow
-
- // Link child frame into the list of children
- if (nsnull != prevKidFrame) {
- prevKidFrame->SetNextSibling(kidFrame);
- } else {
- // Our first child (**blush**)
- if (gsDebug1) printf ("row frame %p, setting first child to %p\n", this, kidFrame);
- mFirstChild = kidFrame;
- SetFirstContentOffset(kidFrame);
- if (gsDebug1) printf("ROW: set first content offset to %d\n", GetFirstContentOffset()); //@@@
- }
- prevKidFrame = kidFrame;
-
- kidIndex++;
- if (frNotComplete == aStatus) {
- // If the child didn't finish layout then it means that it used
- // up all of our available space (or needs us to split).
- mLastContentIsComplete = PR_FALSE;
- break;
- }
- NS_RELEASE(cell); // kid: REFCNT--
}
- if (nsnull != prevKidFrame) {
-#ifdef NS_DEBUG
- if (!IsLastChild(prevKidFrame))
- {
- mGeometricParent->List();
+ // Did we successfully relow our mapped children?
+ if (PR_TRUE == reflowMappedOK) {
+ // Any space left?
+ if (state.availSize.height <= 0) {
+ // No space left. Don't try to pull-up children or reflow unmapped
+ if (NextChildOffset() < mContent->ChildCount()) {
+ aStatus = frNotComplete;
+ }
+ } else if (NextChildOffset() < mContent->ChildCount()) {
+ // Try and pull-up some children from a next-in-flow
+ if (PullUpChildren(aPresContext, state, aMaxElementSize)) {
+ // If we still have unmapped children then create some new frames
+ if (NextChildOffset() < mContent->ChildCount()) {
+ aStatus = ReflowUnmappedChildren(aPresContext, state, aMaxElementSize);
+ }
+ } else {
+ // We were unable to pull-up all the existing frames from the
+ // next in flow
+ aStatus = frNotComplete;
+ }
}
-#endif
- NS_ASSERTION(IsLastChild(prevKidFrame), "unexpected last child");
- SetLastContentOffset(prevKidFrame);
}
- // Return our size and our result
- aDesiredSize.width = cellXOffset;
- aDesiredSize.height = maxSize.height;
- aDesiredSize.ascent = maxAscent;
- aDesiredSize.descent = maxDescent;
- if (nsnull != aMaxElementSize) {
- *aMaxElementSize = kidMaxElementSize;
+ if (frComplete == aStatus) {
+ // Don't forget to add in the bottom margin from our last child.
+ // Only add it in if there's room for it.
+ nscoord margin = state.prevMaxPosBottomMargin -
+ state.prevMaxNegBottomMargin;
}
- SetMaxChildHeight(maxCellHeight); // remember height of tallest child who doesn't have a row span
+
+ // Return our desired rect
+ aDesiredSize.width = aMaxSize.width;
+ aDesiredSize.height = state.maxCellHeight;
#ifdef NS_DEBUG
PostReflowCheck(aStatus);
@@ -326,10 +1019,9 @@ nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
aStatus==frComplete?"Complete":"Not Complete",
aDesiredSize.width, aDesiredSize.height);
}
-
- // testing...
- aStatus = frComplete;
+
return NS_OK;
+
}
NS_METHOD
diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h
index 20446c32384..c10efc5ba8b 100644
--- a/mozilla/layout/tables/nsTableRowFrame.h
+++ b/mozilla/layout/tables/nsTableRowFrame.h
@@ -21,6 +21,8 @@
#include "nscore.h"
#include "nsContainerFrame.h"
+struct RowReflowState;
+
/**
* nsTableRowFrame is the frame that maps table rows
@@ -110,12 +112,60 @@ protected:
/** protected constructor.
* @see NewFrame
*/
- nsTableRowFrame(nsIContent* aContent,
- PRInt32 aIndexInParent,
- nsIFrame* aParentFrame);
+ nsTableRowFrame(nsIContent* aContent,
+ PRInt32 aIndexInParent,
+ nsIFrame* aParentFrame);
+
+ /** destructor */
+ virtual ~nsTableRowFrame();
+
+ nscoord GetTopMarginFor(nsIPresContext* aCX,
+ RowReflowState& aState,
+ nsStyleMolecule* aKidMol);
+
+ void PlaceChild( nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsIFrame* aKidFrame,
+ const nsRect& aKidRect,
+ nsSize* aMaxElementSize,
+ nsSize& aKidMaxElementSize);
+
+ /**
+ * Reflow the frames we've already created
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return true if we successfully reflowed all the mapped children and false
+ * otherwise, e.g. we pushed children to the next in flow
+ */
+ PRBool ReflowMappedChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize);
+
+ /**
+ * Try and pull-up frames from our next-in-flow
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return true if we successfully pulled-up all the children and false
+ * otherwise, e.g. child didn't fit
+ */
+ PRBool PullUpChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize);
+
+ /**
+ * Create new frames for content we haven't yet mapped
+ *
+ * @param aPresContext presentation context to use
+ * @param aState current inline state
+ * @return frComplete if all content has been mapped and frNotComplete
+ * if we should be continued
+ */
+ ReflowStatus ReflowUnmappedChildren(nsIPresContext* aPresContext,
+ RowReflowState& aState,
+ nsSize* aMaxElementSize);
- /** destructor */
- virtual ~nsTableRowFrame();
private:
PRInt32 mTallestCell; // not my height, but the height of my tallest child
diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp
index 06689af4349..e43975e4609 100644
--- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp
+++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp
@@ -95,14 +95,24 @@ struct RowGroupReflowState {
/* ----------- nsTableRowGroupFrame ---------- */
nsTableRowGroupFrame::nsTableRowGroupFrame(nsIContent* aContent,
- PRInt32 aIndexInParent,
- nsIFrame* aParentFrame)
+ PRInt32 aIndexInParent,
+ nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aIndexInParent, aParentFrame)
{
+ mType = aContent->GetTag(); // mType: REFCNT++
}
nsTableRowGroupFrame::~nsTableRowGroupFrame()
{
+ if (nsnull!=mType)
+ NS_RELEASE(mType); // mType: REFCNT--
+}
+
+NS_METHOD nsTableRowGroupFrame::GetRowGroupType(nsIAtom *& aType)
+{
+ NS_ADDREF(mType);
+ aType=mType;
+ return NS_OK;
}
@@ -264,6 +274,8 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
nsSize kidAvailSize(aState.availSize);
+ if (0>=kidAvailSize.height)
+ kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet
nsReflowMetrics desiredSize;
nsIFrame::ReflowStatus status;
@@ -290,7 +302,7 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
// Reflow the child into the available space
status = ReflowChild(kidFrame, aPresContext, desiredSize,
- kidAvailSize, pKidMaxElementSize);
+ kidAvailSize, pKidMaxElementSize);
// Did the child fit?
if ((kidFrame != mFirstChild) &&
@@ -381,6 +393,12 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
break;
}
+ // Add back in the left and right margins, because one row does not
+ // impact another row's width
+ if (PR_FALSE == aState.unconstrainedWidth) {
+ kidAvailSize.width += kidMol->margin.left + kidMol->margin.right;
+ }
+
// Get the next child
kidFrame->GetNextSibling(kidFrame);
@@ -868,10 +886,10 @@ nsTableRowGroupFrame::ResizeReflow( nsIPresContext* aPresContext,
}
// Return our desired rect
- NS_ASSERTION(0