diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index c85127132ec..5046e7cba6d 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -491,6 +491,19 @@ public: */ NS_IMETHOD ReleaseAnonymousContent() = 0; + enum InterruptType {Timeout}; + /** + * Notify aFrame via a reflow command when an aInterruptType event occurs + */ + NS_IMETHOD SendInterruptNotificationTo(nsIFrame* aFrame, + InterruptType aInterruptType) = 0; + /** + * Cancel Notifications to aFrame when an aInterruptType event occurs + */ + NS_IMETHOD CancelInterruptNotificationTo(nsIFrame* aFrame, + InterruptType aInterruptType) = 0; + + /** * See if reflow verification is enabled. To enable reflow verification add * "verifyreflow:1" to your NSPR_LOG_MODULES environment variable diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index cae6809a249..91ff3bce57d 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -840,7 +840,13 @@ public: NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame, nsIFrame** aPlaceholderFrame) const; NS_IMETHOD AppendReflowCommand(nsIReflowCommand* aReflowCommand); - NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowType* aCmdType); + NS_IMETHOD AppendReflowCommandInternal(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue); + NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType); + NS_IMETHOD CancelReflowCommandInternal(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType, + nsVoidArray& aQueue); NS_IMETHOD CancelAllReflowCommands(); NS_IMETHOD IsSafeToFlush(PRBool& aIsSafeToFlush); NS_IMETHOD FlushPendingNotifications(); @@ -1009,6 +1015,10 @@ public: nsIStyleRule* aStyleRule); NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument); + NS_IMETHOD SendInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell::InterruptType aInterruptType); + NS_IMETHOD CancelInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell::InterruptType aInterruptType); #ifdef MOZ_REFLOW_PERF NS_IMETHOD DumpReflows(); NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame); @@ -1040,11 +1050,17 @@ protected: nsresult CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult); nsresult WillCauseReflow(); nsresult DidCauseReflow(); + void ProcessReflowCommand(nsVoidArray& aQueue, + PRBool aAccumulateTime, + nsHTMLReflowMetrics& aDesiredSize, + nsSize& aMaxSize, + nsIRenderingContext& aRenderingContext); nsresult ProcessReflowCommands(PRBool aInterruptible); nsresult GetReflowEventStatus(PRBool* aPending); nsresult SetReflowEventStatus(PRBool aPending); void PostReflowEvent(); - PRBool AlreadyInQueue(nsIReflowCommand* aReflowCommand); + PRBool AlreadyInQueue(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue); friend struct ReflowEvent; // utility to determine if we're in the middle of a drag @@ -1084,7 +1100,11 @@ protected: nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to nsILayoutHistoryState* mHistoryState; // [WEAK] session history owns this PRUint32 mUpdateCount; - nsVoidArray mReflowCommands; + // normal reflow commands + nsVoidArray mReflowCommands; + // reflow commands targeted at each aFrame who calls SendInterruptNotificationTo(aFrame, Timeout); + nsVoidArray mTimeoutReflowCommands; + PRPackedBool mDocumentLoading; PRPackedBool mIsReflowing; PRPackedBool mIsDestroying; @@ -2614,7 +2634,9 @@ NS_IMETHODIMP PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) { // Cancel any pending reflow commands targeted at this frame - CancelReflowCommand(aFrame, nsnull); + CancelReflowCommandInternal(aFrame, nsnull, mReflowCommands); + CancelReflowCommandInternal(aFrame, nsnull, mTimeoutReflowCommands); + // Notify the frame manager if (mFrameManager) { @@ -3106,16 +3128,17 @@ PresShell::EndReflow(nsIDocument *aDocument, nsIPresShell* aShell) // frame it targets is targeted by a pre-existing reflow command in // the queue. PRBool -PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand) +PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue) { - PRInt32 i, n = mReflowCommands.Count(); + PRInt32 i, n = aQueue.Count(); nsIFrame* targetFrame; PRBool inQueue = PR_FALSE; if (NS_SUCCEEDED(aReflowCommand->GetTarget(targetFrame))) { // Iterate over the reflow commands and compare the targeted frames. for (i = 0; i < n; i++) { - nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(i); + nsIReflowCommand* rc = (nsIReflowCommand*) aQueue.ElementAt(i); if (rc) { nsIFrame* targetOfQueuedRC; if (NS_SUCCEEDED(rc->GetTarget(targetOfQueuedRC))) { @@ -3142,8 +3165,28 @@ PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand) return inQueue; } +void +NotifyAncestorFramesOfReflowCommand(nsIPresShell* aPresShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) +{ + if (aRC) { + nsIFrame* target; + aRC->GetTarget(target); + if (target) { + nsIFrame* ancestor; + target->GetParent(&ancestor); + while(ancestor) { + ancestor->ReflowCommandNotify(aPresShell, aRC, aCommandAdded); + ancestor->GetParent(&ancestor); + } + } + } +} + NS_IMETHODIMP -PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) +PresShell::AppendReflowCommandInternal(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue) { #ifdef DEBUG //printf("gShellCounter: %d\n", gShellCounter++); @@ -3166,10 +3209,14 @@ PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) // Add the reflow command to the queue nsresult rv = NS_OK; - if (!AlreadyInQueue(aReflowCommand)) { + // don't check for duplicates on the timeout queue - it is responsiblity of frames + // who call SendInterruptNotificationTo to make sure there are no duplicates + if ((&aQueue == &mTimeoutReflowCommands) || + ((&aQueue == &mReflowCommands) && !AlreadyInQueue(aReflowCommand, aQueue))) { NS_ADDREF(aReflowCommand); - rv = (mReflowCommands.AppendElement(aReflowCommand) ? NS_OK : NS_ERROR_OUT_OF_MEMORY); + rv = (aQueue.AppendElement(aReflowCommand) ? NS_OK : NS_ERROR_OUT_OF_MEMORY); ReflowCommandAdded(aReflowCommand); + NotifyAncestorFramesOfReflowCommand(this, aReflowCommand, PR_TRUE); } // For async reflow during doc load, post a reflow event if we are not batching reflow commands. @@ -3186,6 +3233,12 @@ PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) return rv; } +NS_IMETHODIMP +PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) +{ + return AppendReflowCommandInternal(aReflowCommand, mReflowCommands); +} + // // IsDragInProgress @@ -3209,11 +3262,13 @@ PresShell :: IsDragInProgress ( ) const NS_IMETHODIMP -PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowType* aCmdType) +PresShell::CancelReflowCommandInternal(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType, + nsVoidArray& aQueue) { - PRInt32 i, n = mReflowCommands.Count(); + PRInt32 i, n = aQueue.Count(); for (i = 0; i < n; i++) { - nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(i); + nsIReflowCommand* rc = (nsIReflowCommand*) aQueue.ElementAt(i); if (rc) { nsIFrame* target; if (NS_SUCCEEDED(rc->GetTarget(target))) { @@ -3233,8 +3288,9 @@ PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowT printf("\n"); } #endif - mReflowCommands.RemoveElementAt(i); + aQueue.RemoveElementAt(i); ReflowCommandRemoved(rc); + NotifyAncestorFramesOfReflowCommand(this, rc, PR_FALSE); NS_RELEASE(rc); n--; i--; @@ -3246,18 +3302,33 @@ PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowT return NS_OK; } +NS_IMETHODIMP +PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType) +{ + return CancelReflowCommandInternal(aTargetFrame, aCmdType, mReflowCommands); +} + NS_IMETHODIMP PresShell::CancelAllReflowCommands() { PRInt32 n = mReflowCommands.Count(); nsIReflowCommand* rc; - for (PRInt32 i = 0; i < n; i++) { + PRInt32 i; + for (i = 0; i < n; i++) { rc = NS_STATIC_CAST(nsIReflowCommand*, mReflowCommands.ElementAt(0)); mReflowCommands.RemoveElementAt(0); ReflowCommandRemoved(rc); NS_RELEASE(rc); } + n = mTimeoutReflowCommands.Count(); + for (i = 0; i < n; i++) { + rc = NS_STATIC_CAST(nsIReflowCommand*, mTimeoutReflowCommands.ElementAt(0)); + mTimeoutReflowCommands.RemoveElementAt(0); + ReflowCommandRemoved(rc); + NS_RELEASE(rc); + } return NS_OK; } @@ -5157,21 +5228,54 @@ PresShell::DidCauseReflow() return NS_OK; } +void +PresShell::ProcessReflowCommand(nsVoidArray& aQueue, + PRBool aAccumulateTime, + nsHTMLReflowMetrics& aDesiredSize, + nsSize& aMaxSize, + nsIRenderingContext& aRenderingContext) +{ + // Use RemoveElementAt in case the reflowcommand dispatches a + // new one during its execution. + nsIReflowCommand* rc = (nsIReflowCommand*)aQueue.ElementAt(0); + aQueue.RemoveElementAt(0); + + // Dispatch the reflow command + PRTime beforeReflow, afterReflow; + if (aAccumulateTime) + beforeReflow = PR_Now(); + rc->Dispatch(mPresContext, aDesiredSize, aMaxSize, aRenderingContext); // dispatch the reflow command + if (aAccumulateTime) + afterReflow = PR_Now(); + + ReflowCommandRemoved(rc); + NS_RELEASE(rc); + VERIFY_STYLE_TREE; + + if (aAccumulateTime) { + PRInt64 totalTime, diff; + LL_SUB(diff, afterReflow, beforeReflow); + + LL_I2L(totalTime, mAccumulatedReflowTime); + LL_ADD(totalTime, totalTime, diff); + LL_L2I(mAccumulatedReflowTime, totalTime); + } +} + nsresult PresShell::ProcessReflowCommands(PRBool aInterruptible) { MOZ_TIMER_DEBUGLOG(("Start: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this)); MOZ_TIMER_START(mReflowWatch); - PRTime beforeReflow, afterReflow; - PRInt64 diff; if (0 != mReflowCommands.Count()) { nsHTMLReflowMetrics desiredSize(nsnull); nsIRenderingContext* rcx; nsIFrame* rootFrame; - - mFrameManager->GetRootFrame(&rootFrame); + nsSize maxSize; + rootFrame->GetSize(maxSize); + nsresult rv=CreateRenderingContext(rootFrame, &rcx); if (NS_FAILED(rv)) return rv; @@ -5193,43 +5297,25 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) #endif mIsReflowing = PR_TRUE; + PRInt64 maxTime; while (0 != mReflowCommands.Count()) { - // Use RemoveElementAt in case the reflowcommand dispatches a - // new one during its execution. - nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0); - mReflowCommands.RemoveElementAt(0); - - // Dispatch the reflow command - nsSize maxSize; - rootFrame->GetSize(maxSize); - if (aInterruptible) beforeReflow = PR_Now(); - rc->Dispatch(mPresContext, desiredSize, maxSize, *rcx); // dispatch the reflow command - if (aInterruptible) afterReflow = PR_Now(); - ReflowCommandRemoved(rc); - NS_RELEASE(rc); - VERIFY_STYLE_TREE; - + ProcessReflowCommand(mReflowCommands, aInterruptible, desiredSize, maxSize, *rcx); if (aInterruptible) { - PRInt64 totalTime; - PRInt64 maxTime; - LL_SUB(diff, afterReflow, beforeReflow); - - LL_I2L(totalTime, mAccumulatedReflowTime); - LL_ADD(totalTime, totalTime, diff); - LL_L2I(mAccumulatedReflowTime, totalTime); - LL_I2L(maxTime, gMaxRCProcessingTime); - if (LL_CMP(totalTime, >, maxTime)) + if (LL_CMP(mAccumulatedReflowTime, >, maxTime)) break; } } - NS_IF_RELEASE(rcx); mIsReflowing = PR_FALSE; if (aInterruptible) { - if (mReflowCommands.Count() > 0) { - // Reflow Commands are still queued up. - // Schedule a reflow event to handle them asynchronously. + // process the timeout reflow commands completely + // printf("timeout reflows=%d \n", mTimeoutReflowCommands.Count()); + while (0 != mTimeoutReflowCommands.Count()) { + ProcessReflowCommand(mTimeoutReflowCommands, PR_TRUE, desiredSize, maxSize, *rcx); + } + if (mReflowCommands.Count() > 0) { // Reflow Commands are still queued up. + // Schedule a reflow event to handle the remaining reflow commands asynchronously. PostReflowEvent(); } #ifdef DEBUG @@ -5240,6 +5326,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) #endif mAccumulatedReflowTime = 0; } + NS_IF_RELEASE(rcx); #ifdef DEBUG if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { @@ -5286,6 +5373,33 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) } +nsresult +PresShell::SendInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell::InterruptType aInterruptType) +{ + // create a reflow command targeted at aFrame + nsIReflowCommand* reflowCmd; + nsresult rv; + + // Target the reflow comamnd at aFrame + rv = NS_NewHTMLReflowCommand(&reflowCmd, aFrame, + nsIReflowCommand::Timeout); + if (NS_SUCCEEDED(rv)) { + // Add the reflow command + AppendReflowCommandInternal(reflowCmd, mTimeoutReflowCommands); + NS_RELEASE(reflowCmd); + } + return rv; +} + +nsresult +PresShell::CancelInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell:: InterruptType aInterruptType) + +{ + return CancelReflowCommandInternal(aFrame, nsnull, mTimeoutReflowCommands); +} + nsresult PresShell::GetReflowEventStatus(PRBool* aPending) { @@ -5345,6 +5459,7 @@ PresShell::CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult) return NS_OK; } + nsresult PresShell::ReflowCommandAdded(nsIReflowCommand* aRC) { @@ -6148,6 +6263,7 @@ PresShell::CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) if (mReflowCountMgr) { mReflowCountMgr->Add(aName, (nsReflowReason)aType, aFrame); } + return NS_OK; } diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h index 39f11643920..6427c6c3f83 100644 --- a/mozilla/layout/base/public/nsIFrame.h +++ b/mozilla/layout/base/public/nsIFrame.h @@ -1085,8 +1085,17 @@ public: * to be reflowed. The parent should either propagate the request to its parent frame or * handle the request by generating a nsIReflowCommand::ReflowDirtyChildren reflow command. */ + NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) = 0; + /** + * Called during appending or cancelling a reflow command to give frames notice + * of reflow commands that will be targeted below them. + */ + NS_IMETHOD ReflowCommandNotify(nsIPresShell* aShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) = 0; + /** * Called in style ReResolution to get the frame that contains the style context that is the * parent style context for this frame. diff --git a/mozilla/layout/base/public/nsIPresShell.h b/mozilla/layout/base/public/nsIPresShell.h index c85127132ec..5046e7cba6d 100644 --- a/mozilla/layout/base/public/nsIPresShell.h +++ b/mozilla/layout/base/public/nsIPresShell.h @@ -491,6 +491,19 @@ public: */ NS_IMETHOD ReleaseAnonymousContent() = 0; + enum InterruptType {Timeout}; + /** + * Notify aFrame via a reflow command when an aInterruptType event occurs + */ + NS_IMETHOD SendInterruptNotificationTo(nsIFrame* aFrame, + InterruptType aInterruptType) = 0; + /** + * Cancel Notifications to aFrame when an aInterruptType event occurs + */ + NS_IMETHOD CancelInterruptNotificationTo(nsIFrame* aFrame, + InterruptType aInterruptType) = 0; + + /** * See if reflow verification is enabled. To enable reflow verification add * "verifyreflow:1" to your NSPR_LOG_MODULES environment variable diff --git a/mozilla/layout/base/public/nsIReflowCommand.h b/mozilla/layout/base/public/nsIReflowCommand.h index a3b1140b619..5381a7d37fc 100644 --- a/mozilla/layout/base/public/nsIReflowCommand.h +++ b/mozilla/layout/base/public/nsIReflowCommand.h @@ -94,6 +94,9 @@ public: // Reflow dirty stuff (really a per-frame extension) ReflowDirty, + // The pres shell ran out of time but will guaranteed the reflow command gets processed. + Timeout, + // Trap door for extensions. UserDefined }; diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 93d608990ed..117a82e9b9f 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -3734,6 +3734,15 @@ nsFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) } +inline NS_IMETHODIMP +nsFrame::ReflowCommandNotify(nsIPresShell* aShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) + +{ + return NS_OK; +} + NS_IMETHODIMP nsFrame::GetParentStyleContextProvider(nsIPresContext* aPresContext, nsIFrame** aProviderFrame, diff --git a/mozilla/layout/generic/nsFrame.h b/mozilla/layout/generic/nsFrame.h index a1d592561c0..93dbb1cc0dd 100644 --- a/mozilla/layout/generic/nsFrame.h +++ b/mozilla/layout/generic/nsFrame.h @@ -275,6 +275,9 @@ public: nsPeekOffsetStruct *aPos); NS_IMETHOD GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const; NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); + NS_IMETHOD ReflowCommandNotify(nsIPresShell* aPresShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded); NS_IMETHOD GetParentStyleContextProvider(nsIPresContext* aPresContext, nsIFrame** aProviderFrame, diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index 39f11643920..6427c6c3f83 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -1085,8 +1085,17 @@ public: * to be reflowed. The parent should either propagate the request to its parent frame or * handle the request by generating a nsIReflowCommand::ReflowDirtyChildren reflow command. */ + NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) = 0; + /** + * Called during appending or cancelling a reflow command to give frames notice + * of reflow commands that will be targeted below them. + */ + NS_IMETHOD ReflowCommandNotify(nsIPresShell* aShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) = 0; + /** * Called in style ReResolution to get the frame that contains the style context that is the * parent style context for this frame. diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 93d608990ed..117a82e9b9f 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -3734,6 +3734,15 @@ nsFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) } +inline NS_IMETHODIMP +nsFrame::ReflowCommandNotify(nsIPresShell* aShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) + +{ + return NS_OK; +} + NS_IMETHODIMP nsFrame::GetParentStyleContextProvider(nsIPresContext* aPresContext, nsIFrame** aProviderFrame, diff --git a/mozilla/layout/html/base/src/nsFrame.h b/mozilla/layout/html/base/src/nsFrame.h index a1d592561c0..93dbb1cc0dd 100644 --- a/mozilla/layout/html/base/src/nsFrame.h +++ b/mozilla/layout/html/base/src/nsFrame.h @@ -275,6 +275,9 @@ public: nsPeekOffsetStruct *aPos); NS_IMETHOD GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const; NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); + NS_IMETHOD ReflowCommandNotify(nsIPresShell* aPresShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded); NS_IMETHOD GetParentStyleContextProvider(nsIPresContext* aPresContext, nsIFrame** aProviderFrame, diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index cae6809a249..91ff3bce57d 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -840,7 +840,13 @@ public: NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame, nsIFrame** aPlaceholderFrame) const; NS_IMETHOD AppendReflowCommand(nsIReflowCommand* aReflowCommand); - NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowType* aCmdType); + NS_IMETHOD AppendReflowCommandInternal(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue); + NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType); + NS_IMETHOD CancelReflowCommandInternal(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType, + nsVoidArray& aQueue); NS_IMETHOD CancelAllReflowCommands(); NS_IMETHOD IsSafeToFlush(PRBool& aIsSafeToFlush); NS_IMETHOD FlushPendingNotifications(); @@ -1009,6 +1015,10 @@ public: nsIStyleRule* aStyleRule); NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument); + NS_IMETHOD SendInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell::InterruptType aInterruptType); + NS_IMETHOD CancelInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell::InterruptType aInterruptType); #ifdef MOZ_REFLOW_PERF NS_IMETHOD DumpReflows(); NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame); @@ -1040,11 +1050,17 @@ protected: nsresult CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult); nsresult WillCauseReflow(); nsresult DidCauseReflow(); + void ProcessReflowCommand(nsVoidArray& aQueue, + PRBool aAccumulateTime, + nsHTMLReflowMetrics& aDesiredSize, + nsSize& aMaxSize, + nsIRenderingContext& aRenderingContext); nsresult ProcessReflowCommands(PRBool aInterruptible); nsresult GetReflowEventStatus(PRBool* aPending); nsresult SetReflowEventStatus(PRBool aPending); void PostReflowEvent(); - PRBool AlreadyInQueue(nsIReflowCommand* aReflowCommand); + PRBool AlreadyInQueue(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue); friend struct ReflowEvent; // utility to determine if we're in the middle of a drag @@ -1084,7 +1100,11 @@ protected: nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to nsILayoutHistoryState* mHistoryState; // [WEAK] session history owns this PRUint32 mUpdateCount; - nsVoidArray mReflowCommands; + // normal reflow commands + nsVoidArray mReflowCommands; + // reflow commands targeted at each aFrame who calls SendInterruptNotificationTo(aFrame, Timeout); + nsVoidArray mTimeoutReflowCommands; + PRPackedBool mDocumentLoading; PRPackedBool mIsReflowing; PRPackedBool mIsDestroying; @@ -2614,7 +2634,9 @@ NS_IMETHODIMP PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) { // Cancel any pending reflow commands targeted at this frame - CancelReflowCommand(aFrame, nsnull); + CancelReflowCommandInternal(aFrame, nsnull, mReflowCommands); + CancelReflowCommandInternal(aFrame, nsnull, mTimeoutReflowCommands); + // Notify the frame manager if (mFrameManager) { @@ -3106,16 +3128,17 @@ PresShell::EndReflow(nsIDocument *aDocument, nsIPresShell* aShell) // frame it targets is targeted by a pre-existing reflow command in // the queue. PRBool -PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand) +PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue) { - PRInt32 i, n = mReflowCommands.Count(); + PRInt32 i, n = aQueue.Count(); nsIFrame* targetFrame; PRBool inQueue = PR_FALSE; if (NS_SUCCEEDED(aReflowCommand->GetTarget(targetFrame))) { // Iterate over the reflow commands and compare the targeted frames. for (i = 0; i < n; i++) { - nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(i); + nsIReflowCommand* rc = (nsIReflowCommand*) aQueue.ElementAt(i); if (rc) { nsIFrame* targetOfQueuedRC; if (NS_SUCCEEDED(rc->GetTarget(targetOfQueuedRC))) { @@ -3142,8 +3165,28 @@ PresShell::AlreadyInQueue(nsIReflowCommand* aReflowCommand) return inQueue; } +void +NotifyAncestorFramesOfReflowCommand(nsIPresShell* aPresShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) +{ + if (aRC) { + nsIFrame* target; + aRC->GetTarget(target); + if (target) { + nsIFrame* ancestor; + target->GetParent(&ancestor); + while(ancestor) { + ancestor->ReflowCommandNotify(aPresShell, aRC, aCommandAdded); + ancestor->GetParent(&ancestor); + } + } + } +} + NS_IMETHODIMP -PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) +PresShell::AppendReflowCommandInternal(nsIReflowCommand* aReflowCommand, + nsVoidArray& aQueue) { #ifdef DEBUG //printf("gShellCounter: %d\n", gShellCounter++); @@ -3166,10 +3209,14 @@ PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) // Add the reflow command to the queue nsresult rv = NS_OK; - if (!AlreadyInQueue(aReflowCommand)) { + // don't check for duplicates on the timeout queue - it is responsiblity of frames + // who call SendInterruptNotificationTo to make sure there are no duplicates + if ((&aQueue == &mTimeoutReflowCommands) || + ((&aQueue == &mReflowCommands) && !AlreadyInQueue(aReflowCommand, aQueue))) { NS_ADDREF(aReflowCommand); - rv = (mReflowCommands.AppendElement(aReflowCommand) ? NS_OK : NS_ERROR_OUT_OF_MEMORY); + rv = (aQueue.AppendElement(aReflowCommand) ? NS_OK : NS_ERROR_OUT_OF_MEMORY); ReflowCommandAdded(aReflowCommand); + NotifyAncestorFramesOfReflowCommand(this, aReflowCommand, PR_TRUE); } // For async reflow during doc load, post a reflow event if we are not batching reflow commands. @@ -3186,6 +3233,12 @@ PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) return rv; } +NS_IMETHODIMP +PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand) +{ + return AppendReflowCommandInternal(aReflowCommand, mReflowCommands); +} + // // IsDragInProgress @@ -3209,11 +3262,13 @@ PresShell :: IsDragInProgress ( ) const NS_IMETHODIMP -PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowType* aCmdType) +PresShell::CancelReflowCommandInternal(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType, + nsVoidArray& aQueue) { - PRInt32 i, n = mReflowCommands.Count(); + PRInt32 i, n = aQueue.Count(); for (i = 0; i < n; i++) { - nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(i); + nsIReflowCommand* rc = (nsIReflowCommand*) aQueue.ElementAt(i); if (rc) { nsIFrame* target; if (NS_SUCCEEDED(rc->GetTarget(target))) { @@ -3233,8 +3288,9 @@ PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowT printf("\n"); } #endif - mReflowCommands.RemoveElementAt(i); + aQueue.RemoveElementAt(i); ReflowCommandRemoved(rc); + NotifyAncestorFramesOfReflowCommand(this, rc, PR_FALSE); NS_RELEASE(rc); n--; i--; @@ -3246,18 +3302,33 @@ PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, nsIReflowCommand::ReflowT return NS_OK; } +NS_IMETHODIMP +PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, + nsIReflowCommand::ReflowType* aCmdType) +{ + return CancelReflowCommandInternal(aTargetFrame, aCmdType, mReflowCommands); +} + NS_IMETHODIMP PresShell::CancelAllReflowCommands() { PRInt32 n = mReflowCommands.Count(); nsIReflowCommand* rc; - for (PRInt32 i = 0; i < n; i++) { + PRInt32 i; + for (i = 0; i < n; i++) { rc = NS_STATIC_CAST(nsIReflowCommand*, mReflowCommands.ElementAt(0)); mReflowCommands.RemoveElementAt(0); ReflowCommandRemoved(rc); NS_RELEASE(rc); } + n = mTimeoutReflowCommands.Count(); + for (i = 0; i < n; i++) { + rc = NS_STATIC_CAST(nsIReflowCommand*, mTimeoutReflowCommands.ElementAt(0)); + mTimeoutReflowCommands.RemoveElementAt(0); + ReflowCommandRemoved(rc); + NS_RELEASE(rc); + } return NS_OK; } @@ -5157,21 +5228,54 @@ PresShell::DidCauseReflow() return NS_OK; } +void +PresShell::ProcessReflowCommand(nsVoidArray& aQueue, + PRBool aAccumulateTime, + nsHTMLReflowMetrics& aDesiredSize, + nsSize& aMaxSize, + nsIRenderingContext& aRenderingContext) +{ + // Use RemoveElementAt in case the reflowcommand dispatches a + // new one during its execution. + nsIReflowCommand* rc = (nsIReflowCommand*)aQueue.ElementAt(0); + aQueue.RemoveElementAt(0); + + // Dispatch the reflow command + PRTime beforeReflow, afterReflow; + if (aAccumulateTime) + beforeReflow = PR_Now(); + rc->Dispatch(mPresContext, aDesiredSize, aMaxSize, aRenderingContext); // dispatch the reflow command + if (aAccumulateTime) + afterReflow = PR_Now(); + + ReflowCommandRemoved(rc); + NS_RELEASE(rc); + VERIFY_STYLE_TREE; + + if (aAccumulateTime) { + PRInt64 totalTime, diff; + LL_SUB(diff, afterReflow, beforeReflow); + + LL_I2L(totalTime, mAccumulatedReflowTime); + LL_ADD(totalTime, totalTime, diff); + LL_L2I(mAccumulatedReflowTime, totalTime); + } +} + nsresult PresShell::ProcessReflowCommands(PRBool aInterruptible) { MOZ_TIMER_DEBUGLOG(("Start: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this)); MOZ_TIMER_START(mReflowWatch); - PRTime beforeReflow, afterReflow; - PRInt64 diff; if (0 != mReflowCommands.Count()) { nsHTMLReflowMetrics desiredSize(nsnull); nsIRenderingContext* rcx; nsIFrame* rootFrame; - - mFrameManager->GetRootFrame(&rootFrame); + nsSize maxSize; + rootFrame->GetSize(maxSize); + nsresult rv=CreateRenderingContext(rootFrame, &rcx); if (NS_FAILED(rv)) return rv; @@ -5193,43 +5297,25 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) #endif mIsReflowing = PR_TRUE; + PRInt64 maxTime; while (0 != mReflowCommands.Count()) { - // Use RemoveElementAt in case the reflowcommand dispatches a - // new one during its execution. - nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0); - mReflowCommands.RemoveElementAt(0); - - // Dispatch the reflow command - nsSize maxSize; - rootFrame->GetSize(maxSize); - if (aInterruptible) beforeReflow = PR_Now(); - rc->Dispatch(mPresContext, desiredSize, maxSize, *rcx); // dispatch the reflow command - if (aInterruptible) afterReflow = PR_Now(); - ReflowCommandRemoved(rc); - NS_RELEASE(rc); - VERIFY_STYLE_TREE; - + ProcessReflowCommand(mReflowCommands, aInterruptible, desiredSize, maxSize, *rcx); if (aInterruptible) { - PRInt64 totalTime; - PRInt64 maxTime; - LL_SUB(diff, afterReflow, beforeReflow); - - LL_I2L(totalTime, mAccumulatedReflowTime); - LL_ADD(totalTime, totalTime, diff); - LL_L2I(mAccumulatedReflowTime, totalTime); - LL_I2L(maxTime, gMaxRCProcessingTime); - if (LL_CMP(totalTime, >, maxTime)) + if (LL_CMP(mAccumulatedReflowTime, >, maxTime)) break; } } - NS_IF_RELEASE(rcx); mIsReflowing = PR_FALSE; if (aInterruptible) { - if (mReflowCommands.Count() > 0) { - // Reflow Commands are still queued up. - // Schedule a reflow event to handle them asynchronously. + // process the timeout reflow commands completely + // printf("timeout reflows=%d \n", mTimeoutReflowCommands.Count()); + while (0 != mTimeoutReflowCommands.Count()) { + ProcessReflowCommand(mTimeoutReflowCommands, PR_TRUE, desiredSize, maxSize, *rcx); + } + if (mReflowCommands.Count() > 0) { // Reflow Commands are still queued up. + // Schedule a reflow event to handle the remaining reflow commands asynchronously. PostReflowEvent(); } #ifdef DEBUG @@ -5240,6 +5326,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) #endif mAccumulatedReflowTime = 0; } + NS_IF_RELEASE(rcx); #ifdef DEBUG if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { @@ -5286,6 +5373,33 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) } +nsresult +PresShell::SendInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell::InterruptType aInterruptType) +{ + // create a reflow command targeted at aFrame + nsIReflowCommand* reflowCmd; + nsresult rv; + + // Target the reflow comamnd at aFrame + rv = NS_NewHTMLReflowCommand(&reflowCmd, aFrame, + nsIReflowCommand::Timeout); + if (NS_SUCCEEDED(rv)) { + // Add the reflow command + AppendReflowCommandInternal(reflowCmd, mTimeoutReflowCommands); + NS_RELEASE(reflowCmd); + } + return rv; +} + +nsresult +PresShell::CancelInterruptNotificationTo(nsIFrame* aFrame, + nsIPresShell:: InterruptType aInterruptType) + +{ + return CancelReflowCommandInternal(aFrame, nsnull, mTimeoutReflowCommands); +} + nsresult PresShell::GetReflowEventStatus(PRBool* aPending) { @@ -5345,6 +5459,7 @@ PresShell::CloneStyleSet(nsIStyleSet* aSet, nsIStyleSet** aResult) return NS_OK; } + nsresult PresShell::ReflowCommandAdded(nsIReflowCommand* aRC) { @@ -6148,6 +6263,7 @@ PresShell::CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) if (mReflowCountMgr) { mReflowCountMgr->Add(aName, (nsReflowReason)aType, aFrame); } + return NS_OK; } diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index d84354c0918..000402e9934 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -67,6 +67,21 @@ PRBool CanAllocate(PRInt32 aType, return PR_FALSE; } +// this doesn't work for a col frame which might get its width from a col +PRBool +HasPctValue(nsIFrame* aFrame) +{ + const nsStylePosition* position; + aFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)position); + if (eStyleUnit_Percent == position->mWidth.GetUnit()) { + float percent = position->mWidth.GetPercentValue(); + if (percent > 0.0f) { + return PR_TRUE; + } + } + return PR_FALSE; +} + /* ---------- BasicTableLayoutStrategy ---------- */ MOZ_DECL_CTOR_COUNTER(BasicTableLayoutStrategy) @@ -88,55 +103,56 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() } PRBool BasicTableLayoutStrategy::Initialize(nsIPresContext* aPresContext, - nsSize* aMaxElementSize, - nscoord aMaxWidth, const nsHTMLReflowState& aReflowState) { +#ifdef DEBUG_TABLE_REFLOW_TIMING + nsTableFrame::DebugTimeMethod(nsTableFrame::eInit, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); +#endif ContinuingFrameCheck(); PRBool result = PR_TRUE; // re-init instance variables - mCellSpacingTotal = 0; - mCols = mTableFrame->GetEffectiveCOLSAttribute(); - // assign the width of all fixed-width columns + mCellSpacingTotal = 0; + mCols = mTableFrame->GetEffectiveCOLSAttribute(); + float p2t; aPresContext->GetScaledPixelsToTwips(&p2t); - AssignNonPctColumnWidths(aPresContext, aMaxWidth, aReflowState, p2t); - // set aMaxElementSize here because we compute mMinTableWidth in AssignNonPctColumnWidths - if (nsnull != aMaxElementSize) { - SetMaxElementSize(aMaxElementSize, aReflowState.mComputedPadding); + mTableFrame->SetHasPctCol(PR_FALSE); + + nscoord boxWidth = mTableFrame->CalcBorderBoxWidth(aReflowState); + PRBool hasPctCol = AssignNonPctColumnWidths(aPresContext, boxWidth, aReflowState, p2t); + + mTableFrame->SetHasPctCol(hasPctCol); + + // calc the min, desired, preferred widths from what we know so far + nscoord minWidth, prefWidth; + mTableFrame->CalcMinAndPreferredWidths(aReflowState, minWidth, prefWidth); + if (hasPctCol && mTableFrame->IsAutoWidth()) { + prefWidth = CalcPctAdjTableWidth(aReflowState, boxWidth, p2t); } + // calc the desired width, considering if there is a specified width. + // don't use nsTableFrame::CalcDesiredWidth because it is based on table column widths. + nscoord desWidth = (mTableFrame->IsAutoWidth()) ? PR_MIN(prefWidth, aReflowState.availableWidth) + : prefWidth; + desWidth = PR_MAX(desWidth, minWidth); + mTableFrame->SetMinWidth(minWidth); + mTableFrame->SetDesiredWidth(desWidth); + mTableFrame->SetPreferredWidth(prefWidth); + + mTableFrame->SetNeedStrategyInit(PR_FALSE); + +#ifdef DEBUG_TABLE_REFLOW_TIMING + nsTableFrame::DebugTimeMethod(nsTableFrame::eInit, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); +#endif +#ifdef DEBUG_TABLE_REFLOW + printf("Initialized min=%d des=%d pref=%d\n", minWidth, desWidth, prefWidth); +#endif return result; } -void -BasicTableLayoutStrategy::SetMaxElementSize(nsSize* aMaxElementSize, - const nsMargin& aPadding) -{ - if (nsnull != aMaxElementSize) { - aMaxElementSize->height = 0; - nsMargin borderPadding; - const nsStylePosition* tablePosition; - mTableFrame->GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)tablePosition)); - mTableFrame->GetTableBorder(borderPadding); - borderPadding += aPadding; - nscoord horBorderPadding = borderPadding.left + borderPadding.right; - nscoord minTableWidth = GetTableMinWidth(); - if (tablePosition->mWidth.GetUnit() == eStyleUnit_Coord) { - aMaxElementSize->width = tablePosition->mWidth.GetCoordValue(); - if (minTableWidth + horBorderPadding > aMaxElementSize->width) { - aMaxElementSize->width = minTableWidth + horBorderPadding; - } - } - else { - aMaxElementSize->width = minTableWidth + horBorderPadding; - } - } -} - void BasicTableLayoutStrategy::ContinuingFrameCheck() { #ifdef NS_DEBUG @@ -147,6 +163,7 @@ void BasicTableLayoutStrategy::ContinuingFrameCheck() } PRBool BCW_Wrapup(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, BasicTableLayoutStrategy* aStrategy, nsTableFrame* aTableFrame, PRInt32* aAllocTypes) @@ -154,6 +171,9 @@ PRBool BCW_Wrapup(nsIPresContext* aPresContext, if (aAllocTypes) delete [] aAllocTypes; if (gsDebugBalance) {printf("BalanceColumnWidths ex \n"); aTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);} +#ifdef DEBUG_TABLE_REFLOW_TIMING + nsTableFrame::DebugTimeMethod(nsTableFrame::eBalanceCols, *aTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); +#endif return PR_TRUE; } @@ -174,75 +194,67 @@ ResetPctValues(nsTableFrame* aTableFrame, PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidthIn) + const nsHTMLReflowState& aReflowState) { - if (gsDebugBalance) {printf("BalanceColumnWidths en max=%d count=%d \n", aMaxWidthIn, gsDebugCount++); mTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);} + if (gsDebugBalance) {printf("BalanceColumnWidths en count=%d \n", gsDebugCount++); mTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);} +#ifdef DEBUG_TABLE_REFLOW_TIMING + nsTableFrame::DebugTimeMethod(nsTableFrame::eBalanceCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); +#endif float p2t; aPresContext->GetScaledPixelsToTwips(&p2t); ContinuingFrameCheck(); - if (!aTableStyle) { - NS_ASSERTION(aTableStyle, "bad style arg"); - return PR_FALSE; - } PRInt32 numCols = mTableFrame->GetColCount(); + PRBool tableIsAutoWidth = mTableFrame->IsAutoWidth(); + nscoord horBorderPadding = aReflowState.mComputedBorderPadding.left + + aReflowState.mComputedBorderPadding.right; // determine if the table is auto/fixed and get the fixed width if available - nscoord maxWidth = aMaxWidthIn; - nscoord specifiedTableWidth = mTableFrame->CalcBorderBoxWidth(aReflowState); - PRBool tableIsAutoWidth = mTableFrame->IsAutoWidth(); - // a specifiedTableWidth of <= 0 indicates percentage based - if (!tableIsAutoWidth && (specifiedTableWidth > 0)) { - maxWidth = PR_MIN(specifiedTableWidth, aMaxWidthIn); // specifiedWidth usually == aMaxWidthIn for fixed table + nscoord maxWidth = mTableFrame->CalcBorderBoxWidth(aReflowState); + if (NS_UNCONSTRAINEDSIZE == maxWidth) { + NS_ASSERTION(PR_FALSE, "cannot balance with an unconstrained width"); + return PR_FALSE; } - // reduce the maxWidth by border and padding, since we will be dealing with content width - // XXX should this be done in aMaxWidthIn by the caller? - if (maxWidth != NS_UNCONSTRAINEDSIZE) { - maxWidth -= aReflowState.mComputedBorderPadding.left + - aReflowState.mComputedBorderPadding.right; - maxWidth = PR_MAX(0, maxWidth); - } - // initialize the col percent and cell percent values to 0. ResetPctValues(mTableFrame, numCols); - // set PCT and PCT_ADJ widths on col frames. An auto table returns - // a new table width based on percent cells/cols if they exist + + // An auto table returns a new table width based on percent cells/cols if they exist nscoord perAdjTableWidth = 0; - if ((NS_UNCONSTRAINEDSIZE != maxWidth) || (tableIsAutoWidth)) { - // for an auto width table, use a large basis just so that the quirky - // auto table sizing will get as big as it should - nscoord basis = (NS_UNCONSTRAINEDSIZE == maxWidth) - ? NS_UNCONSTRAINEDSIZE : maxWidth - mCellSpacingTotal; - // this may have to reallocate MIN_ADJ, FIX_ADJ, DES_ADJ if there are - // cells spanning cols which have PCT values - perAdjTableWidth = AssignPctColumnWidths(aReflowState, basis, tableIsAutoWidth, p2t); + if (mTableFrame->HasPctCol()) { + perAdjTableWidth = AssignPctColumnWidths(aReflowState, maxWidth, tableIsAutoWidth, p2t); + perAdjTableWidth = PR_MIN(perAdjTableWidth, maxWidth); + perAdjTableWidth -= horBorderPadding; + perAdjTableWidth = PR_MAX(perAdjTableWidth, 0); } + // reduce the maxWidth by border and padding, since we will be dealing with content width + maxWidth -= horBorderPadding; + maxWidth = PR_MAX(0, maxWidth); + // set the table's columns to the min width + nscoord minTableWidth = 0; PRInt32 colX; for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) continue; nscoord colMinWidth = colFrame->GetMinWidth(); mTableFrame->SetColumnWidth(colX, colMinWidth); + minTableWidth += colMinWidth; } + minTableWidth += mCellSpacingTotal; // if the max width available is less than the min content width for fixed table, we're done - nscoord minTableWidth = GetTableMinWidth(); if (!tableIsAutoWidth && (maxWidth < minTableWidth)) { - return BCW_Wrapup(aPresContext, this, mTableFrame, nsnull); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, nsnull); } // if the max width available is less than the min content width for auto table // that had no % cells/cols, we're done if (tableIsAutoWidth && (maxWidth < minTableWidth) && (0 == perAdjTableWidth)) { - return BCW_Wrapup(aPresContext, this, mTableFrame, nsnull); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, nsnull); } - PRInt32 cellSpacingTotal; // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, FIX_ADJ, PCT // are used and they account for colspan ADJusted values PRInt32 totalWidths[NUM_WIDTHS]; // sum of col widths of a particular type @@ -250,13 +262,12 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont PRInt32 dupedWidths[NUM_WIDTHS]; PRInt32 num0Proportional; - CalculateTotals(cellSpacingTotal, totalCounts, totalWidths, dupedWidths, num0Proportional); + CalculateTotals(totalCounts, totalWidths, dupedWidths, num0Proportional); // auto width table's adjusted width needs cell spacing if (tableIsAutoWidth && perAdjTableWidth > 0) { - perAdjTableWidth = PR_MIN(perAdjTableWidth + cellSpacingTotal, maxWidth); maxWidth = perAdjTableWidth; } - nscoord totalAllocated = totalWidths[MIN_CON] + cellSpacingTotal; + nscoord totalAllocated = totalWidths[MIN_CON] + mCellSpacingTotal; // allocate and initialize arrays indicating what col gets set PRInt32* allocTypes = new PRInt32[numCols]; @@ -274,7 +285,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont } else { AllocateConstrained(maxWidth - totalAllocated, PCT, PR_FALSE, allocTypes, p2t); - return BCW_Wrapup(aPresContext, this, mTableFrame, allocTypes); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, allocTypes); } } // allocate FIX cols @@ -285,7 +296,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont } else { AllocateConstrained(maxWidth - totalAllocated, FIX, PR_TRUE, allocTypes, p2t); - return BCW_Wrapup(aPresContext, this, mTableFrame, allocTypes); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, allocTypes); } } // allocate fixed adjusted cols @@ -296,7 +307,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont } else { AllocateConstrained(maxWidth - totalAllocated, FIX_ADJ, PR_TRUE, allocTypes, p2t); - return BCW_Wrapup(aPresContext, this, mTableFrame, allocTypes); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, allocTypes); } } @@ -309,13 +320,13 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont } else { AllocateConstrained(maxWidth - totalAllocated, DES_CON, PR_TRUE, allocTypes, p2t); - return BCW_Wrapup(aPresContext, this, mTableFrame, allocTypes); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, allocTypes); } } // if this is a nested non auto table and pass1 reflow, we are done if ((maxWidth == NS_UNCONSTRAINEDSIZE) && (!tableIsAutoWidth)) { - return BCW_Wrapup(aPresContext, this, mTableFrame, allocTypes); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, allocTypes); } // allocate the rest to auto columns, with some exceptions @@ -336,7 +347,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont } } - return BCW_Wrapup(aPresContext, this, mTableFrame, allocTypes); + return BCW_Wrapup(aPresContext, aReflowState, this, mTableFrame, allocTypes); } nscoord GetColWidth(nsTableColFrame* aColFrame, @@ -483,10 +494,11 @@ nscoord GetConstrainedWidth(nsTableColFrame* colFrame, void BasicTableLayoutStrategy::ComputeNonPctColspanWidths(const nsHTMLReflowState& aReflowState, PRBool aConsiderPct, - float aPixelToTwips) + float aPixelToTwips, + PRBool* aHasPctCol) { #ifdef DEBUG_TABLE_REFLOW_TIMING - nsTableFrame::DebugTimeNonPctColspans(*mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); + nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctColspans, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); #endif PRInt32 numCols = mTableFrame->GetColCount(); // zero out prior ADJ values @@ -551,10 +563,14 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(const nsHTMLReflowState& aR limit++; } } + // determine if there is a pct col if we are requested to do so + if (aHasPctCol && !*aHasPctCol) { + *aHasPctCol = HasPctValue(cellFrame); + } } } #ifdef DEBUG_TABLE_REFLOW_TIMING - nsTableFrame::DebugTimeNonPctColspans(*mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); + nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctColspans, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); #endif } @@ -837,13 +853,14 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(PRInt32 aWidthInd return result; } + // XXX percent left and right padding are not figured in the calculations // The table frame needs to be used as the percent base because the reflow // state may have an unconstrained width. There should probably be a frame // state bit indicating that horizontal padding is percentage based. // Determine min, desired, fixed, and proportional sizes for the cols and -// and calculate min/max table width +// and calculate min/max table width. Return true if there is at least one pct cell or col PRBool BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPresContext, nscoord aMaxWidth, @@ -851,7 +868,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre float aPixelToTwips) { #ifdef DEBUG_TABLE_REFLOW_TIMING - nsTableFrame::DebugTimeNonPctCols(*mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); + nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); #endif if (gsDebugAssign) {printf("AssignNonPctColWidths en max=%d count=%d \n", aMaxWidth, gsDebugCount++); mTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);} PRBool rv = PR_FALSE; @@ -860,6 +877,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre nscoord spacingX = mTableFrame->GetCellSpacingX(); PRInt32 colX, rowX; mCellSpacingTotal = 0; + PRBool hasPctCol = PR_FALSE; // return value PRInt32 rawPropTotal = -1; // total of numbers of the type 1*, 2*, etc PRInt32 numColsForColsAttr = 0; // Nav Quirks cols attribute for equal width cols @@ -921,6 +939,9 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre } } } + if (!hasPctCol && HasPctValue(cellFrame)) { // see if there is a pct cell + hasPctCol = PR_TRUE; + } } // Nav/IE Quirk like above @@ -943,11 +964,11 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre colFrame->SetWidth(FIX, PR_MAX(fixWidth, minWidth)); } + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); // determine if there is a proportional column either from html4 // proportional width on a col or Nav Quirks cols attr if (fixWidth <= 0) { nscoord proportion = WIDTH_NOT_SET; - nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); if (eStyleUnit_Proportional == colStyleWidth.GetUnit()) { proportion = colStyleWidth.GetIntValue(); } @@ -967,12 +988,21 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre colFrame->SetConstraint(colConstraint); } } + if (!hasPctCol) { // see if there is a pct col + if (eStyleUnit_Percent == colStyleWidth.GetUnit()) { + float percent = colStyleWidth.GetPercentValue(); + if (percent > 0.0f) { + hasPctCol = PR_TRUE; + } + } + } } if (mCellSpacingTotal > 0) { mCellSpacingTotal += spacingX; // add last cell spacing on right } - ComputeNonPctColspanWidths(aReflowState, PR_FALSE, aPixelToTwips); + PRBool* pctRequest = (hasPctCol) ? nsnull : &hasPctCol; + ComputeNonPctColspanWidths(aReflowState, PR_FALSE, aPixelToTwips, pctRequest); // figure the proportional widths for porportional cols if (rawPropTotal > 0) { @@ -1039,9 +1069,9 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre if (gsDebugAssign) {printf("AssignNonPctColWidths ex\n"); mTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);} #ifdef DEBUG_TABLE_REFLOW_TIMING - nsTableFrame::DebugTimeNonPctCols(*mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); + nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); #endif - return rv; + return hasPctCol; } void @@ -1075,7 +1105,7 @@ nscoord WrapupAssignPctColumnWidths(nsTableFrame* aTableFrame, const nsHTMLReflowState& aReflowState, nscoord aValue) { - nsTableFrame::DebugTimePctCols(*aTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); + nsTableFrame::DebugTimeMethod(nsTableFrame::ePctCols, *aTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE); return aValue; } #else @@ -1087,15 +1117,143 @@ inline nscoord WrapupAssignPctColumnWidths(nsTableFrame* aTableFrame, } #endif +nscoord +BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState, + nscoord aAvailWidthIn, + float aPixelToTwips) +{ + NS_ASSERTION(mTableFrame->IsAutoWidth() && mTableFrame->HasPctCol(), "invalid call"); + + PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); // consider cols at end without orig cells + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 colX, rowX; + + // For an auto table, determine the potentially new percent adjusted width based + // on percent cells/cols. This probably should only be a NavQuirks thing, since + // a percentage based cell or column on an auto table should force the column to auto + nscoord basis = 0; + float* rawPctValues = new float[numCols]; // store the raw pct values, allow for spans past the effective numCols + if (!rawPctValues) return NS_ERROR_OUT_OF_MEMORY; + for (colX = 0; colX < numCols; colX++) { + rawPctValues[colX] = 0.0f; + } + + nsMargin borderPadding = mTableFrame->GetBorderPadding(aReflowState); + nscoord availWidth = aAvailWidthIn; + if (NS_UNCONSTRAINEDSIZE != availWidth) { + // adjust the avail width to exclude table border, padding and cell spacing + availWidth -= borderPadding.left + borderPadding.right + mCellSpacingTotal; + } + + for (colX = 0; colX < numCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + if (!colFrame) continue; + nscoord maxColBasis = -1; + // Scan the cells in the col + for (rowX = 0; rowX < numRows; rowX++) { + PRBool originates; + PRInt32 colSpan; + nsTableCellFrame* cellFrame = mTableFrame->GetCellInfoAt(rowX, colX, &originates, &colSpan); + if (!originates) continue; // skip cells that don't originate in the col + // see if the cell has a style percent width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + if (percent > 0.0f) { + // calculate the preferred width of the cell based on fixWidth and desWidth + nscoord cellDesWidth = 0; + float spanPct = percent / float(colSpan); + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* spanFrame = mTableFrame->GetColFrame(colX + spanX); + if (!spanFrame) continue; + cellDesWidth += spanFrame->GetWidth(DES_CON); // don't consider DES_ADJ + rawPctValues[colX + spanX] = PR_MAX(rawPctValues[colX + spanX], spanPct); + } + // figure the basis using the cell's desired width and percent + nscoord colBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)cellDesWidth / percent), aPixelToTwips); + maxColBasis = PR_MAX(maxColBasis, colBasis); + } + } + } + if (-1 == maxColBasis) { + // see if the col has a style percent width specified + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Percent == colStyleWidth.GetUnit()) { + float percent = colStyleWidth.GetPercentValue(); + maxColBasis = 0; + if (percent > 0.0f) { + rawPctValues[colX] = PR_MAX(rawPctValues[colX], percent); + nscoord desWidth = colFrame->GetWidth(DES_CON); // don't consider DES_ADJ + maxColBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)desWidth / percent), aPixelToTwips); + } + } + } + basis = PR_MAX(basis, maxColBasis); + } // end for (colX .. + + float perTotal = 0.0f; // total of percentage constrained cols and/or cells in cols + nscoord fixWidthTotal = 0; // total of fixed widths of all cols + PRInt32 numPerCols = 0; // number of colums that have percentage constraints + nscoord fixDesTotal = 0; // total of fix or des widths of cols + nscoord fixDesTotalNoPct = 0; // total of fix or des widths of cols without pct + + for (colX = 0; colX < numCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord fixWidth = colFrame->GetFixWidth(); + nscoord fixDesWidth = (fixWidth > 0) ? fixWidth : colFrame->GetDesWidth(); + fixDesTotal += fixDesWidth; + if (rawPctValues[colX] + perTotal > 1.0f) { + rawPctValues[colX] = PR_MAX(1.0f - perTotal, 0.0f); + } + if (rawPctValues[colX] > 0.0f) { + numPerCols++; + perTotal += rawPctValues[colX]; + } + else { + fixDesTotalNoPct += fixDesWidth; + } + } + delete [] rawPctValues; // destroy the raw pct values + // If there are no pct cells or cols, there is nothing to do. + if ((0 == numPerCols) || (0.0f == perTotal)) { + NS_ASSERTION(PR_FALSE, "invalid call"); + return 0; + } + // If there is only one col and it is % based, it won't affect anything + if ((1 == numCols) && (numCols == numPerCols)) { + return 0; + } + + // compute a basis considering total percentages and the desired width of everything else + if ((perTotal > 0.0f) && (perTotal < 1.0f)) { + nscoord otherBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)fixDesTotalNoPct / (1.0f - perTotal)), aPixelToTwips); + basis = PR_MAX(basis, otherBasis); + } + else if ((fixDesTotalNoPct > 0) && (NS_UNCONSTRAINEDSIZE != availWidth)) { // make the basis as big as possible + basis = availWidth; // the 100% cols force as big a width as possible + } + basis = PR_MAX(basis, fixDesTotal); + basis = PR_MIN(basis, availWidth); // don't exceed the max we were given + + if (NS_UNCONSTRAINEDSIZE != availWidth) { + // add back the table border, padding and cell spacing + basis += borderPadding.left + borderPadding.right + mCellSpacingTotal; + } + + return basis; +} + // Determine percentage col widths for each col frame nscoord BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflowState, - nscoord aBasisIn, + nscoord aAvailWidth, PRBool aTableIsAutoWidth, float aPixelToTwips) { #ifdef DEBUG_TABLE_REFLOW_TIMING - nsTableFrame::DebugTimePctCols(*mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); + nsTableFrame::DebugTimeMethod(nsTableFrame::ePctCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE); #endif mTableFrame->SetHasCellSpanningPctCol(PR_FALSE); // this gets refigured below PRInt32 numRows = mTableFrame->GetRowCount(); @@ -1105,12 +1263,8 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow PRInt32 colX, rowX; nscoord basis; // basis to use for percentage based calculations - if (!aTableIsAutoWidth) { - if (NS_UNCONSTRAINEDSIZE == aBasisIn) { - // don't do the calculations on unconstrained basis - return WrapupAssignPctColumnWidths(mTableFrame, aReflowState, 0); - } - basis = aBasisIn; + if (aTableIsAutoWidth) { + basis = CalcPctAdjTableWidth(aReflowState, aAvailWidth, aPixelToTwips); } else { // For an auto table, determine the potentially new percent adjusted width based @@ -1205,20 +1359,11 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow if ((1 == numCols) && (numCols == numPerCols)) { return WrapupAssignPctColumnWidths(mTableFrame, aReflowState, 0); } - - // compute a basis considering total percentages and the desired width of everything else - if (perTotal < 1.0f) { - if (perTotal > 0.0f) { - nscoord otherBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)fixDesTotalNoPct / (1.0f - perTotal)), aPixelToTwips); - basis = PR_MAX(basis, otherBasis); - } - } - else if ((fixDesTotalNoPct > 0) && (NS_UNCONSTRAINEDSIZE != aBasisIn)) { // make the basis as big as possible - basis = aBasisIn; - } - basis = PR_MAX(basis, fixDesTotal); - basis = PR_MIN(basis, aBasisIn); // don't exceed the max we were given + basis = aAvailWidth; } + // adjust the basis to exclude table border, padding and cell spacing + nsMargin borderPadding = mTableFrame->GetBorderPadding(aReflowState); + basis -= borderPadding.left + borderPadding.right + mCellSpacingTotal; nscoord colPctTotal = 0; @@ -1301,7 +1446,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow if (colFrame->GetWidth(PCT) > 0) { mTableFrame->SetHasCellSpanningPctCol(PR_TRUE); // recompute the MIN_ADJ, FIX_ADJ, and DES_ADJ values - ComputeNonPctColspanWidths(aReflowState, PR_TRUE, aPixelToTwips); + ComputeNonPctColspanWidths(aReflowState, PR_TRUE, aPixelToTwips, nsnull); done = PR_TRUE; break; } @@ -1400,78 +1545,23 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow ReduceOverSpecifiedPctCols(NSToCoordRound(((float)(colPctTotal - 100)) * 0.01f * (float)basis)); } + // adjust the basis to include table border, padding and cell spacing + basis += borderPadding.left + borderPadding.right + mCellSpacingTotal; return WrapupAssignPctColumnWidths(mTableFrame, aReflowState, basis); } -nscoord BasicTableLayoutStrategy::GetTableMinWidth() const -{ - nscoord minWidth = 0; - nscoord spacingX = mTableFrame->GetCellSpacingX(); - PRInt32 numCols = mTableFrame->GetColCount(); - for (PRInt32 colX = 0; colX < numCols; colX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - if (!colFrame) continue; - minWidth += PR_MAX(colFrame->GetMinWidth(), colFrame->GetWidth(MIN_ADJ)); - if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) { - minWidth += spacingX; - } - } - // if it is not a degenerate table, add the last spacing on the right - if (minWidth > 0) { - minWidth += spacingX; - } - return minWidth; -} - -nscoord BasicTableLayoutStrategy::GetTableMaxWidth(const nsHTMLReflowState& aReflowState) const -{ - nscoord maxWidth = 0; - - if (mTableFrame->IsAutoWidth()) { - nscoord spacingX = mTableFrame->GetCellSpacingX(); - PRInt32 numCols = mTableFrame->GetColCount(); - for (PRInt32 colX = 0; colX < numCols; colX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - if (!colFrame) continue; - nscoord width = colFrame->GetPctWidth(); - if (width <= 0) { - width = colFrame->GetFixWidth(); - if (width <= 0) { - width = colFrame->GetWidth(MIN_PRO); - if (width <= 0) { - width = colFrame->GetDesWidth(); - } - } - } - maxWidth += width; - if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) { - maxWidth += spacingX; - } - } - // if it is not a degenerate table, add the last spacing on the right - if (maxWidth > 0) { - maxWidth += spacingX; - } - } - else { - maxWidth = PR_MAX(GetTableMinWidth(), aReflowState.mComputedWidth); - } - return maxWidth; -} // calculate totals by width type. The logic here is kept in synch with // that in CanAllocate. aDupedWidths (duplicatd) are widths that will be // allocated in BalanceColumnWidths before aTotalsWidths (e.g. aTotalWidths[PCT] // will have aDuplicatedWidths[PCT] consisting of the MIN widths of cols which // have a PCT width). -void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, - PRInt32* aTotalCounts, +void BasicTableLayoutStrategy::CalculateTotals(PRInt32* aTotalCounts, PRInt32* aTotalWidths, PRInt32* aDupedWidths, PRInt32& a0ProportionalCount) { //mTableFrame->Dump(PR_TRUE, PR_FALSE); - aCellSpacing = 0; for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { aTotalCounts[widthX] = 0; aTotalWidths[widthX] = 0; @@ -1486,9 +1576,6 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) continue; - if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) { - aCellSpacing += spacingX; - } nscoord minCol = colFrame->GetMinWidth(); aTotalCounts[MIN_CON]++; aTotalWidths[MIN_CON] += minCol; @@ -1539,10 +1626,6 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, aDupedWidths[DES_CON] += minCol; } } - // if it is not a degenerate table, add the last spacing on the right - if (numCols > 0) { - aCellSpacing += spacingX; - } } @@ -1778,186 +1861,6 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, AC_Wrapup(mTableFrame, numConstrainedCols, colInfo); } -// XXX this function will be improved after the colspan algorithms have been extracted -// from AssignNonPctColumnWidths and AssignPctColumnWidths. For now, pessimistic -// assumptions are made -PRBool BasicTableLayoutStrategy::ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const -{ - if (!mTableFrame) - return PR_TRUE; - - const nsStylePosition* cellPosition; - aCellFrame.GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - const nsStyleCoord& styleWidth = cellPosition->mWidth; - - PRInt32 colIndex; - aCellFrame.GetColIndex(colIndex); - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - if (!colFrame) return PR_FALSE; - nscoord colSpan = mTableFrame->GetEffectiveColSpan(aCellFrame); - - if (aPrevStyleWidth) { - nsTableColFrame* colSpanFrame = colFrame; - // see if this cell is responsible for setting a fixed or percentage based col - for (PRInt32 span = 1; span <= colSpan; span++) { - if (!colSpanFrame) continue; - if (&aCellFrame == colSpanFrame->GetConstrainingCell()) - return PR_TRUE; // assume that the style change will affect cols - if (span < colSpan) - colSpanFrame = mTableFrame->GetColFrame(colIndex + span); - } - // if we get here, the cell was not responsible for a fixed or percentage col - switch(aPrevStyleWidth->GetUnit()) { - case eStyleUnit_Percent: - if (eStyleUnit_Percent == styleWidth.GetUnit()) { - // PCT to PCT - if (aPrevStyleWidth->GetPercentValue() < styleWidth.GetPercentValue()) - return PR_TRUE; // XXX see comments above - } - // PCT to FIX and PCT to AUTO changes have no effect since PCT allocations - // are the highest priority and the cell's previous PCT value did not - // cause it to be responsible for setting any cells PCT_ADJ - case eStyleUnit_Coord: - if (eStyleUnit_Percent == styleWidth.GetUnit()) { - // FIX to PCT - return PR_TRUE; // XXX see comments above - } - else if (eStyleUnit_Coord == styleWidth.GetUnit()) { - // FIX to FIX - nscoord newWidth = styleWidth.GetCoordValue(); - if (aPrevStyleWidth->GetCoordValue() < newWidth) { - if (colSpan > 1) - return PR_TRUE; // XXX see comments above - if (newWidth > colFrame->GetFixWidth()) - return PR_TRUE; // XXX see comments above - } - } - // FIX to AUTO results in no column changes here - case eStyleUnit_Auto: - if (eStyleUnit_Percent == styleWidth.GetUnit()) { - // AUTO to PCT - return PR_TRUE; // XXX see comments above - } - else if (eStyleUnit_Coord == styleWidth.GetUnit()) { - // AUTO to FIX - return PR_TRUE; // XXX see comments above - } - // AUTO to AUTO is not a style change - default: - break; - } - } - return PR_FALSE; -} - - -// XXX this function will be improved after the colspan algorithms have been extracted -// from AssignNonPctColumnWidths and AssignPctColumnWidths. For now, pessimistic -// assumptions are made -PRBool BasicTableLayoutStrategy::ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth) const -{ - if (aConsiderMinWidth || !mTableFrame) - return PR_TRUE; - - PRInt32 colIndex; - aCellFrame.GetColIndex(colIndex); - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - if (!colFrame) return PR_FALSE; - nscoord colSpan = mTableFrame->GetEffectiveColSpan(aCellFrame); - - // check to see if DES_CON can affect columns - nsTableColFrame* spanFrame = colFrame; - for (PRInt32 span = 0; span < colSpan; span++) { - if (!spanFrame) return PR_FALSE; - // see if the column width is constrained - if ((spanFrame->GetPctWidth() > 0) || (spanFrame->GetFixWidth() > 0) || - (spanFrame->GetWidth(MIN_PRO) > 0)) { - if ((spanFrame->GetWidth(PCT_ADJ) > 0) && (spanFrame->GetWidth(PCT) <= 0)) { - return PR_TRUE; - } - if ((spanFrame->GetWidth(FIX_ADJ) > 0) && (spanFrame->GetWidth(FIX) <= 0)) { - return PR_TRUE; // its unfortunate that the balancing algorithms cause this - } - } - else { - return PR_TRUE; // XXX need to add cases if table has coord width specified - } - if (span < colSpan - 1) - spanFrame = mTableFrame->GetColFrame(colIndex + span + 1); - } - return PR_FALSE; -} - -PRBool BasicTableLayoutStrategy::ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const -{ - PRInt32 colIndex; - aCellFrame.GetColIndex(colIndex); - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - if (!colFrame) return PR_TRUE; - nscoord colSpan = mTableFrame->GetEffectiveColSpan(aCellFrame); - - nscoord cellMin = aCellFrame.GetPass1MaxElementSize().width; - nscoord cellDes = aCellFrame.GetMaximumWidth(); - nscoord colMin = colFrame->GetMinWidth(); - nscoord colDes = colFrame->GetDesWidth(); - - PRBool minChanged = PR_TRUE; - if (((cellMin > aPrevCellMin) && (cellMin <= colMin)) || - ((cellMin <= aPrevCellMin) && (aPrevCellMin <= colMin))) { - minChanged = PR_FALSE; - } - if (minChanged) { - return PR_FALSE; // XXX add cases where table has coord width and cell is constrained - } - - PRBool desChanged = PR_TRUE; - if (((cellDes > aPrevCellDes) && (cellDes <= colDes)) || - (cellDes == aPrevCellDes)) { - // XXX This next check causes a problem if the cell's desired width shrinks, - // because the comparison (aPresCellDes <= colDes) will always be TRUE and - // so we always end up setting desChanged to PR_FALSE. That means the column - // won't shrink like it should -#if 0 - || ((cellDes < aPrevCellDes) && (aPrevCellDes <= colDes))) { -#endif - desChanged = PR_FALSE; - } - - if (1 == colSpan) { - // see if the column width is constrained - if ((colFrame->GetPctWidth() > 0) || (colFrame->GetFixWidth() > 0) || - (colFrame->GetWidth(MIN_PRO) > 0)) { - if ((colFrame->GetWidth(PCT_ADJ) > 0) && (colFrame->GetWidth(PCT) <= 0)) { - if (desChanged) { - return PR_FALSE; // XXX add cases where table has coord width - } - } - nscoord colFix = colFrame->GetWidth(FIX); - if ((colFrame->GetWidth(FIX_ADJ) > 0) && (colFix <= 0)) { - if (desChanged) { - return PR_FALSE; // its unfortunate that the balancing algorithms cause this - // XXX add cases where table has coord width - } - } - if ((colFix > 0) && (desChanged) && (cellDes < aPrevCellDes) && (aPrevCellDes == colFix)) { - return PR_FALSE; - } - } - else { // the column width is not constrained - if (desChanged) { - return PR_FALSE; - } - } - } - else { - return PR_FALSE; // XXX this needs a lot of cases - } - return PR_TRUE; -} PRBool BasicTableLayoutStrategy::IsColumnInList(const PRInt32 colIndex, PRInt32* colIndexes, @@ -1979,8 +1882,7 @@ PRBool BasicTableLayoutStrategy::IsColumnInList(const PRInt32 colIndex, PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) { PRBool result = PR_FALSE; - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(aColIndex, colFrame); + nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex); nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); switch (colStyleWidth.GetUnit()) { case eStyleUnit_Coord: diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h index acc1a4f64f4..c74be043a29 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h @@ -59,31 +59,16 @@ public: * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param */ virtual PRBool Initialize(nsIPresContext* aPresContext, - nsSize* aMaxElementSize, - nscoord aMaxSize, const nsHTMLReflowState& aReflowState); - /** compute the max element size of the table. - * assumes that Initialize has been called - */ - virtual void SetMaxElementSize(nsSize* aMaxElementSize, - const nsMargin& aPadding); - - void SetMinAndMaxTableContentWidths(); - /** Called during resize reflow to determine the new column widths * @param aTableStyle - the resolved style for mTableFrame * @param aReflowState - the reflow state for mTableFrame * @param aMaxWidth - the computed max width for columns to fit into */ virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth); + const nsHTMLReflowState& aReflowState); - // these accessors are mostly for debugging purposes - nscoord GetTableMinWidth() const; - nscoord GetTableMaxWidth(const nsHTMLReflowState& aReflowState) const; nscoord GetCOLSAttribute() const; void Dump(PRInt32 aIndent); @@ -112,10 +97,12 @@ protected: * @param aReflowState - the reflow state of the table * @param aConsiderPct - if true, consider columns that have pct widths and are spanned by the cell * @param aPixelToTwips- the number of twips in a pixel. + * @param aHasPctCol - if not null, then set *aHasPctCol to true if there is a pct cell or col */ void ComputeNonPctColspanWidths(const nsHTMLReflowState& aReflowState, PRBool aConsiderPct, - float aPixelToTwips); + float aPixelToTwips, + PRBool* aHasPctCol); /** * main helper for above. For min width calculations, it can get called up to @@ -144,10 +131,13 @@ protected: PRBool aTableIsAutoWidth, float aPixelToTwips); + nscoord CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState, + nscoord aAvailWidth, + float aPixelToTwips); + void ReduceOverSpecifiedPctCols(nscoord aExcess); - void CalculateTotals(PRInt32& aCellSpacing, - PRInt32* aTotalCounts, + void CalculateTotals(PRInt32* aTotalCounts, PRInt32* aTotalWidths, PRInt32* aMinWidths, PRInt32& a0ProportionalCount); @@ -194,19 +184,6 @@ protected: PRInt32*& aOutColumnIndexes); void ContinuingFrameCheck(); - // see nsTableFrame::ColumnsCanBeInvalidatedBy - PRBool ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const; - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - PRBool ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth = PR_FALSE) const; - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - PRBool ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const; - #ifdef DEBUG void SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const { *aResult = sizeof(*this); diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp index 1d4e51622fd..3fd5571d268 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp @@ -38,9 +38,7 @@ FixedTableLayoutStrategy::~FixedTableLayoutStrategy() } PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth) + const nsHTMLReflowState& aReflowState) { return PR_TRUE; } @@ -240,33 +238,6 @@ FixedTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre return PR_TRUE; } -PRBool FixedTableLayoutStrategy::ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const -{ - return ColumnsCanBeInvalidatedBy(aCellFrame); -} - -PRBool FixedTableLayoutStrategy::ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth) const - -{ - nscoord rowIndex; - aCellFrame.GetRowIndex(rowIndex); - if (0 == rowIndex) { - // It is not worth the effort to determine if the col or cell determined the col - // width. Since rebalancing the columns is fairly trival in this strategy, just force it. - return PR_TRUE; - } - return PR_FALSE; -} - -PRBool FixedTableLayoutStrategy::ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const -{ - // take the easy way out, see comments above. - return !ColumnsCanBeInvalidatedBy(aCellFrame); -} diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h index fef1d1d1bc1..211493dc3ac 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h @@ -59,22 +59,7 @@ public: * @param aMaxWidth - the computed max width for columns to fit into */ virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth); - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - PRBool ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const; - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - PRBool ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth = PR_FALSE) const; - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - PRBool ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const; + const nsHTMLReflowState& aReflowState); #ifdef DEBUG void SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const { diff --git a/mozilla/layout/html/table/src/makefile.win b/mozilla/layout/html/table/src/makefile.win index e5b2676feb7..3486cbd2ee3 100644 --- a/mozilla/layout/html/table/src/makefile.win +++ b/mozilla/layout/html/table/src/makefile.win @@ -24,7 +24,7 @@ DEPTH=..\..\..\.. LIBRARY_NAME=layouthtmltable_s MODULE=raptor -DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN -DoffDEBUG_TABLE_REFLOW_TIMING -DoffDEBUG_TABLE_REFLOW_TIMING_DETAIL +DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN -DoffDEBUG_TABLE_REFLOW -DoffDEBUG_TABLE_REFLOW_TIMING -DoffDEBUG_TABLE_REFLOW_TIMING_DETAIL CPPSRCS= nsCellMap.cpp \ nsTableCellFrame.cpp \ diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index 025c693a42f..5645d8b89fa 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -443,14 +443,13 @@ PRBool nsTableCellMap::RowHasSpanningCells(PRInt32 aRowIndex) PRBool nsTableCellMap::ColIsSpannedInto(PRInt32 aColIndex) { - nsCellMap* cellMap = mFirstMap; - while (cellMap) { - if (cellMap->ColIsSpannedInto(*this, aColIndex)) { - return PR_TRUE; - } - cellMap = cellMap->GetNextSibling(); + PRBool result = PR_FALSE; + + PRInt32 colCount = mCols.Count(); + if ((aColIndex >= 0) && (aColIndex < colCount)) { + result = (PRBool) ((nsColInfo *)mCols.ElementAt(aColIndex))->mNumCellsSpan; } - return PR_FALSE; + return result; } PRBool nsTableCellMap::ColHasSpanningCells(PRInt32 aColIndex) @@ -1781,26 +1780,6 @@ PRBool nsCellMap::RowHasSpanningCells(nsTableCellMap& aMap, return PR_FALSE; } -PRBool nsCellMap::ColIsSpannedInto(nsTableCellMap& aMap, - PRInt32 aColIndex) -{ - PRInt32 numColsInTable = aMap.GetColCount(); - if ((0 > aColIndex) || (aColIndex >= numColsInTable)) { - return PR_FALSE; - } - for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) { - CellData* cd = GetCellAt(aMap, rowIndex, aColIndex); - if (cd) { // there's really a cell at (aRowIndex, colIndex) - if (cd->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span - if (cd->IsColSpan() && GetCellFrame(rowIndex, aColIndex, *cd, PR_FALSE)) { // XXX why the last check - return PR_TRUE; - } - } - } - } - return PR_FALSE; -} - PRBool nsCellMap::ColHasSpanningCells(nsTableCellMap& aMap, PRInt32 aColIndex) { diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h index 67e7d92489f..c24cf0cf98b 100644 --- a/mozilla/layout/html/table/src/nsCellMap.h +++ b/mozilla/layout/html/table/src/nsCellMap.h @@ -226,9 +226,6 @@ public: PRBool RowHasSpanningCells(nsTableCellMap& aMap, PRInt32 aRowIndex); - PRBool ColIsSpannedInto(nsTableCellMap& aMap, - PRInt32 aColIndex); - PRBool ColHasSpanningCells(nsTableCellMap& aMap, PRInt32 aColIndex); diff --git a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h index ab51b227a24..a65c0b12547 100644 --- a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h @@ -44,16 +44,8 @@ public: * @param aComputedWidth the computed size of the table */ virtual PRBool Initialize(nsIPresContext* aPresContext, - nsSize* aMaxElementSize, - nscoord aComputedWidth, const nsHTMLReflowState& aBorderPadding)=0; - /** compute the max-element-size for the table - * @param aMaxElementSize [OUT] width field set to the min legal width of the table - */ - virtual void SetMaxElementSize(nsSize* aMaxElementSize, - const nsMargin& aPadding)=0; - /** assign widths for each column, taking into account the table content, the effective style, * the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect. * @param aTableStyle the resolved style for the table @@ -62,41 +54,12 @@ public: */ virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth)=0; + const nsHTMLReflowState& aReflowState)=0; - /** return the computed max "natural" size of the table. - * this is the sum of the desired size of the content taking into account table - * attributes, but NOT factoring in the available size the table is laying out into. - * the actual table width in a given situation will depend on the available size - * provided by the parent (especially for percent-width tables.) - */ - virtual nscoord GetTableMaxWidth(const nsHTMLReflowState& aReflowState) const = 0; - - /** return the computed minimum possible size of the table. - * this is the sum of the minimum sizes of the content taking into account table - * attributes, but NOT factoring in the available size the table is laying out into. - * the actual table width in a given situation will depend on the available size - * provided by the parent (especially for percent-width tables.) - */ - virtual nscoord GetTableMinWidth() const = 0; /** return the value of the COLS attribute, used for balancing column widths */ virtual nscoord GetCOLSAttribute() const = 0; - // see nsTableFrame::ColumnsCanBeInvalidatedBy - virtual PRBool ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const = 0; - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - virtual PRBool ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth = PR_FALSE) const = 0; - - // see nsTableFrame::ColumnsCanBeInvalidatedBy - virtual PRBool ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const = 0; #ifdef DEBUG virtual void SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const = 0; diff --git a/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp b/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp index 507be889da2..f22c1d4b04b 100644 --- a/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp +++ b/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp @@ -19,7 +19,7 @@ * * Contributor(s): */ - +#if 0 #include "nsIPresContext.h" #include "nsTableBorderCollapser.h" #include "nsTableFrame.h" @@ -191,8 +191,7 @@ void nsTableBorderCollapser::ComputeLeftBorderForEdgeAt(nsIPresContext* aPresCon mTableFrame.GetStyleData(eStyleStruct_Border, ((const nsStyleStruct *&)borderStyleData)); styles.AppendElement((void*)borderStyleData); // 2. colgroup - nsTableColFrame* colFrame; - mTableFrame.GetColumnFrame(aColIndex, colFrame); + nsTableColFrame* colFrame = mTableFrame.GetColFrame(aColIndex); nsIFrame* colGroupFrame; colFrame->GetParent(&colGroupFrame); colGroupFrame->GetStyleData(eStyleStruct_Border, ((const nsStyleStruct *&)borderStyleData)); @@ -869,3 +868,4 @@ void nsTableBorderCollapser::GetMaxBorder(PRInt32 aStartRowIndex, } } } +#endif diff --git a/mozilla/layout/html/table/src/nsTableBorderCollapser.h b/mozilla/layout/html/table/src/nsTableBorderCollapser.h index cdaef89cf1a..74658b485ac 100644 --- a/mozilla/layout/html/table/src/nsTableBorderCollapser.h +++ b/mozilla/layout/html/table/src/nsTableBorderCollapser.h @@ -21,7 +21,7 @@ */ #ifndef nsTableBorderCollapser_h__ #define nsTableBorderCollapser_h__ - +#if 0 #include "nsIStyleContext.h" class nsTableFrame; @@ -154,6 +154,7 @@ inline nsBorderEdges* nsTableBorderCollapser::GetEdges() } #endif +#endif diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index af33bc6820d..9b80468e407 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -56,7 +56,6 @@ nsTableCellFrame::nsTableCellFrame() { mColIndex = 0; mPriorAvailWidth = 0; - mBorderEdges = nsnull; #ifdef DEBUG_TABLE_REFLOW_TIMING mTimer = new nsReflowTimer(this); mBlockTimer = new nsReflowTimer(this); @@ -65,7 +64,6 @@ nsTableCellFrame::nsTableCellFrame() nsTableCellFrame::~nsTableCellFrame() { - delete mBorderEdges; #ifdef DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflowDone(this); #endif @@ -169,29 +167,8 @@ void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) { nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { + if ((NS_SUCCEEDED(rv)) && tableFrame) { SetColIndex(aColIndex); - if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle()) { - if (mBorderEdges) delete mBorderEdges; // this could be non null during a reinitialization - mBorderEdges = new nsBorderEdges; - mBorderEdges->mOutsideEdge=PR_FALSE; - - PRInt32 rowspan = tableFrame->GetEffectiveRowSpan(*this); - PRInt32 i; - for (i=0; imEdges[NS_SIDE_LEFT].AppendElement(borderToAdd); - borderToAdd = new nsBorderEdge(); - mBorderEdges->mEdges[NS_SIDE_RIGHT].AppendElement(borderToAdd); - } - PRInt32 colspan = tableFrame->GetEffectiveColSpan(*this); - for (i=0; imEdges[NS_SIDE_TOP].AppendElement(borderToAdd); - borderToAdd = new nsBorderEdge(); - mBorderEdges->mEdges[NS_SIDE_BOTTOM].AppendElement(borderToAdd); - } - } } } @@ -220,28 +197,6 @@ nsresult nsTableCellFrame::SetColIndex(PRInt32 aColIndex) return rv; } - -void nsTableCellFrame::SetBorderEdgeLength(PRUint8 aSide, - PRInt32 aIndex, - nscoord aLength) -{ - NS_PRECONDITION(mBorderEdges, "haven't allocated border edges struct"); - if ((NS_SIDE_LEFT==aSide) || (NS_SIDE_RIGHT==aSide)) - { - PRInt32 baseRowIndex; - GetRowIndex(baseRowIndex); - PRInt32 rowIndex = aIndex-baseRowIndex; - nsBorderEdge *border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(rowIndex)); - if (border) { - border->mLength = aLength; - } - } - else { - NS_ASSERTION(PR_FALSE, "bad arg aSide passed to SetBorderEdgeLength"); - } -} - - NS_METHOD nsTableCellFrame::Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -258,38 +213,30 @@ NS_METHOD nsTableCellFrame::Paint(nsIPresContext* aPresContext, if (disp->IsVisibleOrCollapsed()) { const nsStyleColor* myColor = (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); - - //TABLECELL SELECTION PRInt16 displaySelection; displaySelection = DisplaySelection(aPresContext); - if (displaySelection) - { + if (displaySelection) { nsFrameState frameState; PRBool isSelected; GetFrameState(&frameState); isSelected = (frameState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT; - if (isSelected) - { + if (isSelected) { nsCOMPtr shell; nsresult result = aPresContext->GetShell(getter_AddRefs(shell)); if (NS_FAILED(result)) return result; nsCOMPtr frameSelection; result = shell->GetFrameSelection(getter_AddRefs(frameSelection)); - if (NS_SUCCEEDED(result)) - { + if (NS_SUCCEEDED(result)) { PRBool tableCellSelectionMode; result = frameSelection->GetTableCellSelection(&tableCellSelectionMode); - if (NS_SUCCEEDED(result) && tableCellSelectionMode) - { + if (NS_SUCCEEDED(result) && tableCellSelectionMode) { frameSelection->GetTableCellSelectionStyleColor(&myColor); - if(displaySelection==nsISelectionController::SELECTION_DISABLED) - { + if(displaySelection==nsISelectionController::SELECTION_DISABLED) { ((nsStyleColor *)myColor)->mBackgroundColor = NS_RGB(176,176,176);// disabled color } - else - { + else { nsILookAndFeel* look = nsnull; if (NS_SUCCEEDED(aPresContext->GetLookAndFeel(&look)) && look) { look->GetColor(nsILookAndFeel::eColor_TextSelectBackground, ((nsStyleColor *)myColor)->mBackgroundColor);//VERY BAD CAST..TEMPORARY @@ -319,30 +266,21 @@ NS_METHOD nsTableCellFrame::Paint(nsIPresContext* aPresContext, // empty cells do not render their border PRBool renderBorder = PR_TRUE; - if (PR_TRUE==GetContentEmpty()) - { - if (NS_STYLE_TABLE_EMPTY_CELLS_HIDE==cellTableStyle->mEmptyCells) + if (GetContentEmpty()) { + if (NS_STYLE_TABLE_EMPTY_CELLS_HIDE == cellTableStyle->mEmptyCells) renderBorder=PR_FALSE; } - if (PR_TRUE==renderBorder) - { + if (renderBorder) { PRIntn skipSides = GetSkipSides(); - nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly + nsTableFrame* tableFrame = nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { + if ((NS_SUCCEEDED(rv)) && tableFrame) { const nsStyleTable* tableStyle; tableFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)tableStyle)); - if (NS_STYLE_BORDER_SEPARATE == tableFrame->GetBorderCollapseStyle()) - { + if (NS_STYLE_BORDER_SEPARATE == tableFrame->GetBorderCollapseStyle()) { nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *myBorder, mStyleContext, skipSides); } - else - { - nsCSSRendering::PaintBorderEdges(aPresContext, aRenderingContext, this, - aDirtyRect, rect, mBorderEdges, mStyleContext, skipSides); - } } } } @@ -401,10 +339,10 @@ NS_METHOD nsTableCellFrame::Paint(nsIPresContext* aPresContext, } NS_IMETHODIMP -nsTableCellFrame::GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, +nsTableCellFrame::GetFrameForPoint(nsIPresContext* aPresContext, + const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame) + nsIFrame** aFrame) { // this should act like a block, so we need to override return GetFrameForPointUsing(aPresContext, aPoint, nsnull, aWhichLayer, (aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND), aFrame); @@ -413,9 +351,9 @@ nsTableCellFrame::GetFrameForPoint(nsIPresContext* aPresContext, //null range means the whole thing NS_IMETHODIMP nsTableCellFrame::SetSelected(nsIPresContext* aPresContext, - nsIDOMRange *aRange, - PRBool aSelected, - nsSpread aSpread) + nsIDOMRange* aRange, + PRBool aSelected, + nsSpread aSpread) { //traverse through children unselect tables #if 0 @@ -441,12 +379,10 @@ nsTableCellFrame::SetSelected(nsIPresContext* aPresContext, return result; nsCOMPtr frameSelection; result = shell->GetFrameSelection(getter_AddRefs(frameSelection)); - if (NS_SUCCEEDED(result) && frameSelection) - { + if (NS_SUCCEEDED(result) && frameSelection) { PRBool tableCellSelectionMode; result = frameSelection->GetTableCellSelection(&tableCellSelectionMode); - if (NS_SUCCEEDED(result) && tableCellSelectionMode) - { + if (NS_SUCCEEDED(result) && tableCellSelectionMode) { nsRect frameRect; GetRect(frameRect); nsRect rect(0, 0, frameRect.width, frameRect.height); @@ -479,71 +415,8 @@ PRBool nsTableCellFrame::ParentDisablesSelection() const //override default beha return nsFrame::ParentDisablesSelection(); } -void nsTableCellFrame::SetBorderEdge(PRUint8 aSide, - PRInt32 aRowIndex, - PRInt32 aColIndex, - nsBorderEdge *aBorder, - nscoord aOddAmountToAdd) -{ - NS_PRECONDITION(mBorderEdges, "haven't allocated border edges struct"); - nsBorderEdge *border = nsnull; - switch (aSide) - { - case NS_SIDE_TOP: - { - PRInt32 baseColIndex; - GetColIndex(baseColIndex); - PRInt32 colIndex = aColIndex-baseColIndex; - border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(colIndex)); - mBorderEdges->mMaxBorderWidth.top = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.top); - break; - } - case NS_SIDE_BOTTOM: - { - PRInt32 baseColIndex; - GetColIndex(baseColIndex); - PRInt32 colIndex = aColIndex-baseColIndex; - border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(colIndex)); - mBorderEdges->mMaxBorderWidth.bottom = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.bottom); - break; - } - - case NS_SIDE_LEFT: - { - PRInt32 baseRowIndex; - GetRowIndex(baseRowIndex); - PRInt32 rowIndex = aRowIndex-baseRowIndex; - border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(rowIndex)); - mBorderEdges->mMaxBorderWidth.left = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.left); - break; - } - - case NS_SIDE_RIGHT: - { - PRInt32 baseRowIndex; - GetRowIndex(baseRowIndex); - PRInt32 rowIndex = aRowIndex-baseRowIndex; - border = (nsBorderEdge *)(mBorderEdges->mEdges[aSide].ElementAt(rowIndex)); - mBorderEdges->mMaxBorderWidth.right = PR_MAX(aBorder->mWidth+aOddAmountToAdd, mBorderEdges->mMaxBorderWidth.right); - break; - } - } - if (nsnull!=border) { - *border=*aBorder; - border->mWidth += aOddAmountToAdd; - } - else { - //XXX determine why this was asserting (after beta) - //NS_ASSERTION(PR_FALSE, "bad border edge state"); - } -} - -/** - * - * Align the cell's child frame within the cell - * - */ +// Align the cell's child frame within the cell void nsTableCellFrame::VerticallyAlignChild(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nscoord aMaxAscent) @@ -644,8 +517,7 @@ PRInt32 nsTableCellFrame::GetRowSpan() PRInt32 rowSpan=1; nsIHTMLContent *hc=nsnull; nsresult rv = mContent->QueryInterface(kIHTMLContentIID, (void**) &hc); - if (NS_OK==rv) - { + if (NS_OK==rv) { nsHTMLValue val; hc->GetHTMLAttribute(nsHTMLAtoms::rowspan, val); if (eHTMLUnit_Integer == val.GetUnit()) { @@ -661,8 +533,7 @@ PRInt32 nsTableCellFrame::GetColSpan() PRInt32 colSpan=1; nsIHTMLContent *hc=nsnull; nsresult rv = mContent->QueryInterface(kIHTMLContentIID, (void**) &hc); - if (NS_OK==rv) - { + if (NS_OK==rv) { nsHTMLValue val; hc->GetHTMLAttribute(nsHTMLAtoms::colspan, val); if (eHTMLUnit_Integer == val.GetUnit()) { @@ -719,7 +590,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, aStatus = NS_FRAME_COMPLETE; nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight); nsSize maxElementSize; - nsSize *pMaxElementSize = aDesiredSize.maxElementSize; + nsSize* pMaxElementSize = aDesiredSize.maxElementSize; if (NS_UNCONSTRAINEDSIZE==aReflowState.availableWidth) pMaxElementSize = &maxElementSize; @@ -745,8 +616,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, availSize.height -= topInset+bottomInset; PRBool isStyleChanged = PR_FALSE; - if (eReflowReason_Incremental == aReflowState.reason) - { + if (eReflowReason_Incremental == aReflowState.reason) { // We *must* do this otherwise incremental reflow that's // passing through will not work right. nsIFrame* next; @@ -757,14 +627,11 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, // first determine if this frame is the target or not nsIFrame *target=nsnull; rv = aReflowState.reflowCommand->GetTarget(target); - if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target)) - { - if (this==target) - { + if ((PR_TRUE==NS_SUCCEEDED(rv)) && target) { + if (this == target) { nsIReflowCommand::ReflowType type; aReflowState.reflowCommand->GetType(type); - if (nsIReflowCommand::StyleChanged==type) - { + if (nsIReflowCommand::StyleChanged == type) { isStyleChanged = PR_TRUE; } else { @@ -926,15 +793,20 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.descent += kidSize.descent; if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = kidSize.mMaximumWidth + leftInset + rightInset; + aDesiredSize.mMaximumWidth = kidSize.mMaximumWidth; + if (NS_UNCONSTRAINEDSIZE != aDesiredSize.mMaximumWidth) { + aDesiredSize.mMaximumWidth += leftInset + rightInset; + } } - if (nsnull!=aDesiredSize.maxElementSize) { + if (aDesiredSize.maxElementSize) { *aDesiredSize.maxElementSize = *pMaxElementSize; - if (0!=pMaxElementSize->height) { + if (0 != pMaxElementSize->height) { aDesiredSize.maxElementSize->height += topInset + bottomInset; } aDesiredSize.maxElementSize->width = PR_MAX(smallestMinWidth, aDesiredSize.maxElementSize->width); - aDesiredSize.maxElementSize->width += leftInset + rightInset; + if (NS_UNCONSTRAINEDSIZE != aDesiredSize.maxElementSize->width) { + aDesiredSize.maxElementSize->width += leftInset + rightInset; + } } // remember my desired size for this reflow SetDesiredSize(aDesiredSize); @@ -997,8 +869,7 @@ PRBool nsTableCellFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefau aResult = aValue.GetPixelValue(); else if (aValue.GetUnit() == eHTMLUnit_Empty) aResult = aDefault; - else - { + else { NS_ERROR("Unit must be pixel or empty"); return PR_FALSE; } @@ -1065,10 +936,9 @@ void nsTableCellFrame::MapVAlignAttribute(nsIPresContext* aPresContext, nsTableF } // check if valign is set on the cell's COL (or COLGROUP by inheritance) - nsTableColFrame* colFrame; PRInt32 colIndex; GetColIndex(colIndex); - aTableFrame->GetColumnFrame(colIndex, colFrame); + nsTableColFrame* colFrame = aTableFrame->GetColFrame(colIndex); if (colFrame) { const nsStyleText* colTextStyle; colFrame->GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)colTextStyle); @@ -1111,10 +981,9 @@ void nsTableCellFrame::MapHAlignAttribute(nsIPresContext* aPresContext, } // check if halign is set on the cell's COL (or COLGROUP by inheritance) - nsTableColFrame* colFrame; PRInt32 colIndex; GetColIndex(colIndex); - aTableFrame->GetColumnFrame(colIndex, colFrame); + nsTableColFrame* colFrame = aTableFrame->GetColFrame(colIndex); if (colFrame) { const nsStyleText* colTextStyle; colFrame->GetStyleData(eStyleStruct_Text,(const nsStyleStruct *&)colTextStyle); @@ -1251,37 +1120,6 @@ NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) /* ----- methods from CellLayoutData ----- */ -/** - * Given an Edge, find the opposing edge (top<-->bottom, left<-->right) - * - **/ -PRUint8 nsTableCellFrame::GetOpposingEdge(PRUint8 aEdge) -{ - PRUint8 result; - - switch (aEdge) - { - case NS_SIDE_LEFT: - result = NS_SIDE_RIGHT; - break; - - case NS_SIDE_RIGHT: - result = NS_SIDE_LEFT; - break; - - case NS_SIDE_TOP: - result = NS_SIDE_BOTTOM; - break; - - case NS_SIDE_BOTTOM: - result = NS_SIDE_TOP; - break; - - default: - result = NS_SIDE_TOP; - } - return result; -} void nsTableCellFrame::GetCellBorder(nsMargin& aBorder, @@ -1292,13 +1130,13 @@ nsTableCellFrame::GetCellBorder(nsMargin& aBorder, return; } - if (NS_STYLE_BORDER_COLLAPSE==aTableFrame->GetBorderCollapseStyle()) { - NS_PRECONDITION(mBorderEdges, "haven't allocated border edges struct"); - aBorder = mBorderEdges->mMaxBorderWidth; - } else { + if (NS_STYLE_BORDER_SEPARATE == aTableFrame->GetBorderCollapseStyle()) { const nsStyleBorder* borderData; GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)borderData); borderData->GetBorder(aBorder); + } + else { + NS_ASSERTION(PR_FALSE, "not implemented"); } } diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index 49616891d71..1f890957fa5 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -90,16 +90,6 @@ public: void InitCellFrame(PRInt32 aColIndex); - void SetBorderEdge(PRUint8 aSide, - PRInt32 aRowIndex, - PRInt32 aColIndex, - nsBorderEdge *border, - nscoord aOddAmountToAdd); - - void SetBorderEdgeLength(PRUint8 aSide, - PRInt32 aIndex, - nscoord aLength); - /** instantiate a new instance of nsTableCellFrame. * @param aResult the new object is returned in this out-param @@ -246,8 +236,6 @@ private: //XXX: aTableFrame can be removed as soon as border-collapse inherits correctly void GetCellBorder(nsMargin &aBorder, nsTableFrame *aTableFrame); - PRUint8 GetOpposingEdge(PRUint8 aEdge); - protected: friend class nsTableRowFrame; @@ -281,8 +269,6 @@ protected: nsSize mPass1MaxElementSize; public: - nsBorderEdges *mBorderEdges; // one list of border segments for each side of the table frame - // used only for the collapsing border model #ifdef DEBUG_TABLE_REFLOW_TIMING nsReflowTimer* mTimer; diff --git a/mozilla/layout/html/table/src/nsTableColFrame.cpp b/mozilla/layout/html/table/src/nsTableColFrame.cpp index c6dc23288d0..96db2e79769 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColFrame.cpp @@ -40,11 +40,10 @@ nsTableColFrame::nsTableColFrame() - : nsFrame(), - mProportion(WIDTH_NOT_SET), - mIsAnonymous(PR_FALSE) + : nsFrame() { // note that all fields are initialized to 0 by nsFrame::operator new + mBits.mIsAnonymous = PR_FALSE; ResetSizingInfo(); SetType(eColContent); } @@ -98,7 +97,6 @@ nsStyleCoord nsTableColFrame::GetStyleWidth() const void nsTableColFrame::ResetSizingInfo() { nsCRT::memset(mWidths, WIDTH_NOT_SET, NUM_WIDTHS * sizeof(PRInt32)); - mProportion = 0; mConstraint = eNoConstraint; mConstrainingCell = nsnull; } @@ -226,7 +224,7 @@ void nsTableColFrame::Dump(PRInt32 aIndent) indent[aIndent] = 0; printf("%s**START COL DUMP** colIndex=%d isAnonymous=%d constraint=%d", - indent, mColIndex, mIsAnonymous, mConstraint); + indent, mColIndex, mBits.mIsAnonymous, mConstraint); printf("\n%s widths=", indent); for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { printf("%d ", mWidths[widthX]); diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index 9b6470fe41d..c055b49629d 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -34,7 +34,7 @@ class nsTableCellFrame; // XXX MIN_ADJ, DES_ADJ, PCT_ADJ, DES_PRO can probably go away and be replaced // by MIN_CON, DES_CON, PCT_CON, DES_CON saving 16 bytes per col frame #define WIDTH_NOT_SET -1 -#define NUM_WIDTHS 9 +#define NUM_WIDTHS 10 #define NUM_MAJOR_WIDTHS 3 // MIN, DES, FIX #define MIN_CON 0 // minimum width required of the content + padding #define DES_CON 1 // desired width of the content + padding @@ -45,7 +45,7 @@ class nsTableCellFrame; #define PCT 6 // percent width of cell or col #define PCT_ADJ 7 // percent width of cell or col from percent colspan #define MIN_PRO 8 // desired width due to proportional s or cols attribute - +#define FINAL 9 // width after the table has been balanced, considering all of the others enum nsColConstraint { eNoConstraint = 0, ePixelConstraint = 1, // pixel width @@ -148,7 +148,7 @@ public: * Return false if this col was constructed due to content having display type of table-col */ PRBool IsAnonymous(); - void SetIsAnonymous(PRBool aValue); + void SetIsAnonymous(PRBool aValue); void ResetSizingInfo(); @@ -157,8 +157,9 @@ public: protected: struct ColBits { - unsigned int mType:4; - unsigned int mUnused:28; + unsigned mType:4; + unsigned mIsAnonymous:1; + unsigned mUnused:27; } mBits; nsTableColFrame(); @@ -169,10 +170,8 @@ protected: // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO nscoord mWidths[NUM_WIDTHS]; - nscoord mProportion; // proportion for porportional width col nsColConstraint mConstraint; nsTableCellFrame* mConstrainingCell; - PRPackedBool mIsAnonymous; }; inline PRInt32 nsTableColFrame::GetColIndex() const @@ -188,10 +187,10 @@ inline void nsTableColFrame::SetConstraint(nsColConstraint aConstraint) { mConstraint = aConstraint;} inline PRBool nsTableColFrame::IsAnonymous() -{ return mIsAnonymous; } +{ return (PRBool)mBits.mIsAnonymous; } inline void nsTableColFrame::SetIsAnonymous(PRBool aIsAnonymous) -{ mIsAnonymous = aIsAnonymous; } +{ mBits.mIsAnonymous = (unsigned)aIsAnonymous; } inline void nsTableColFrame::SetConstrainingCell(nsTableCellFrame* aCellFrame) { mConstrainingCell = aCellFrame; } diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp index 2a6b8700c7a..cfc7ed91df1 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -103,9 +103,7 @@ nsTableColGroupFrame::AddColsToTable(nsIPresContext& aPresContext, nsresult rv = NS_OK; nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (!(NS_SUCCEEDED(rv) && tableFrame && aFirstFrame)) { - return rv; - } + if (!tableFrame || !aFirstFrame) return NS_ERROR_NULL_POINTER; // set the col indices of the col frames and and add col info to the table PRInt32 colIndex = aFirstColIndex; @@ -229,6 +227,8 @@ nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext, { nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); + if (!tableFrame) return NS_ERROR_NULL_POINTER; + if (!aChildList) { nsIFrame* firstChild; tableFrame->CreateAnonymousColFrames(*aPresContext, *this, GetSpan(), eColAnonymousColGroup, @@ -266,36 +266,6 @@ nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext, return NS_OK; } -// Helper function. It marks the table frame as dirty and generates -// a reflow command -nsresult -nsTableColGroupFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aTableFrame) -{ - nsFrameState frameState; - nsIFrame* tableParentFrame; - nsIReflowCommand* reflowCmd; - nsresult rv; - - // Mark the table frame as dirty - aTableFrame->GetFrameState(&frameState); - frameState |= NS_FRAME_IS_DIRTY; - aTableFrame->SetFrameState(frameState); - - // Target the reflow comamnd at its parent frame - aTableFrame->GetParent(&tableParentFrame); - rv = NS_NewHTMLReflowCommand(&reflowCmd, tableParentFrame, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - // Add the reflow command - rv = aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - - return rv; -} - NS_IMETHODIMP nsTableColGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -338,10 +308,13 @@ nsTableColGroupFrame::InsertColsReflow(nsIPresContext& aPresContext, nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnWidths(); + if (!tableFrame) return; + + // XXX this could be optimized with much effort + tableFrame->SetNeedStrategyInit(PR_TRUE); // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(&aPresContext, aPresShell, tableFrame); + nsTableFrame::AppendDirtyReflowCommand(&aPresShell, tableFrame); } void @@ -361,6 +334,14 @@ nsTableColGroupFrame::RemoveChild(nsIPresContext& aPresContext, ResetColIndices(&aPresContext, this, colIndex, nextChild); } } + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + if (!tableFrame) return; + + // XXX this could be optimized with much effort + tableFrame->SetNeedStrategyInit(PR_TRUE); + // Generate a reflow command so we reflow the table + nsTableFrame::AppendDirtyReflowCommand(nsTableFrame::GetPresShellNoAddref(&aPresContext), tableFrame); } // this removes children form the last col group (eColGroupAnonymousCell) in the @@ -413,13 +394,14 @@ nsTableColGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); - if (tableFrame) { - tableFrame->RemoveCol(*aPresContext, this, colIndex, PR_TRUE, PR_TRUE); - } + if (!tableFrame) return NS_ERROR_NULL_POINTER; - tableFrame->InvalidateColumnWidths(); + tableFrame->RemoveCol(*aPresContext, this, colIndex, PR_TRUE, PR_TRUE); + + // XXX This could probably be optimized with much effort + tableFrame->SetNeedStrategyInit(PR_TRUE); // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + nsTableFrame::AppendDirtyReflowCommand(&aPresShell, tableFrame); } else { mFrames.DestroyFrame(aPresContext, aOldFrame); @@ -593,9 +575,8 @@ NS_METHOD nsTableColGroupFrame::IR_StyleChanged(nsIPresContext* aPresCo // XXX: we can optimize this when we know which style attribute changed nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && tableFrame) { - tableFrame->InvalidateColumnWidths(); - tableFrame->InvalidateFirstPassCache(); + if (tableFrame) { + tableFrame->SetNeedStrategyInit(PR_TRUE); } return rv; } @@ -620,11 +601,12 @@ NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext* aPresC nsTableFrame *tableFrame=nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { + if (tableFrame) { // compare the new col count to the old col count. // If they are the same, we just need to rebalance column widths // If they differ, we need to fix up other column groups and the column cache - tableFrame->InvalidateColumnWidths(); + // XXX for now assume the worse + tableFrame->SetNeedStrategyInit(PR_TRUE); } return rv; } diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.h b/mozilla/layout/html/table/src/nsTableColGroupFrame.h index 20df5ba2de0..a73f9ecdba8 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.h @@ -209,10 +209,6 @@ protected: nsReflowStatus& aStatus, nsIFrame * aNextFrame); - nsresult AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aTableFrame); - // data members PRInt32 mColCount; diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 1913ad06a74..6eabdaa0c3d 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -69,19 +69,22 @@ static void GetPlaceholderFor(nsIPresContext& aPresContext, nsIFrame& aFrame, ns static const PRInt32 kColumnWidthIncrement=10; -/* ----------- InnerTableReflowState ---------- */ +/******************************************************************************** + ** nsTableReflowState ** + ********************************************************************************/ -struct InnerTableReflowState { +struct nsTableReflowState { - // Our reflow state + // the real reflow state const nsHTMLReflowState& reflowState; - // The body's available size (computed from the body's parent) + nsReflowReason reason; + + // The table's available size nsSize availSize; - // Flags for whether the max size is unconstrained - PRBool unconstrainedWidth; - PRBool unconstrainedHeight; + // Stationary x-offset + nscoord x; // Running y-offset nscoord y; @@ -92,32 +95,50 @@ struct InnerTableReflowState { // The first body section row group frame, i.e. not a header or footer nsIFrame* firstBodySection; - // border/padding - nsMargin mBorderPadding; - - InnerTableReflowState(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - const nsMargin& aBorderPadding) - : reflowState(aReflowState), mBorderPadding(aBorderPadding) + nsTableReflowState(const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowReason aReason, + nscoord aAvailWidth, + nscoord aAvailHeight) + : reflowState(aReflowState) { - y=0; // border/padding??? + Init(aTableFrame, aReason, aAvailWidth, aAvailHeight); + } - unconstrainedWidth = PRBool(aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE); - unconstrainedHeight = PRBool(aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE); + void Init(nsTableFrame& aTableFrame, + nsReflowReason aReason, + nscoord aAvailWidth, + nscoord aAvailHeight) + { + reason = aReason; - availSize.width = aReflowState.availableWidth; - if (!unconstrainedWidth) { - availSize.width -= aBorderPadding.left + aBorderPadding.right; + nsTableFrame* table = (nsTableFrame*)aTableFrame.GetFirstInFlow(); + nsMargin borderPadding = table->GetBorderPadding(reflowState); + + x = borderPadding.left; + y = borderPadding.top; + + availSize.width = aAvailWidth; + if (NS_UNCONSTRAINEDSIZE != availSize.width) { + availSize.width -= borderPadding.left + borderPadding.right; } - availSize.height = aReflowState.availableHeight; - if (!unconstrainedHeight) { - availSize.height -= aBorderPadding.top + aBorderPadding.bottom; + availSize.height = aAvailHeight; + if (NS_UNCONSTRAINEDSIZE != availSize.height) { + availSize.height -= borderPadding.top + borderPadding.bottom; } - footerFrame = nsnull; + footerFrame = nsnull; firstBodySection = nsnull; } + + nsTableReflowState(const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame) + : reflowState(aReflowState) + { + Init(aTableFrame, aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight); + } + }; const nsHTMLReflowState* @@ -130,6 +151,17 @@ GetGrandParentReflowState(const nsHTMLReflowState& aInnerRS) return rs; } +nscoord +GetHorBorderPaddingWidth(const nsHTMLReflowState& aReflowState, + nsTableFrame* aTableFrame) +{ + nsMargin borderPadding = aTableFrame->GetBorderPadding(aReflowState); + return borderPadding.left + borderPadding.right; +} + +/******************************************************************************** + ** nsTableFrame ** + ********************************************************************************/ NS_IMETHODIMP nsTableFrame::GetFrameType(nsIAtom** aType) const @@ -141,33 +173,22 @@ nsTableFrame::GetFrameType(nsIAtom** aType) const } -/* --------------------- nsTableFrame -------------------- */ - nsTableFrame::nsTableFrame() : nsHTMLContainerFrame(), mCellMap(nsnull), mTableLayoutStrategy(nsnull), mPercentBasisForRows(0), - mPreferredWidth(0) + mPreferredWidth(0), + mNumDescendantReflowsPending(0), + mNumDescendantTimeoutReflowsPending(0) { - mBits.mColumnWidthsSet = PR_FALSE; - mBits.mColumnWidthsValid = PR_FALSE; - mBits.mFirstPassValid = PR_FALSE; - mBits.mIsInvariantWidth = PR_FALSE; - mBits.mMaximumWidthValid = PR_FALSE; - mBits.mCellSpansPctCol = PR_FALSE; - // XXX We really shouldn't do this, but if we don't then we'll have a - // problem with the tree control... -#if 0 - mColumnWidthsLength = 0; - mColumnWidths = nsnull; -#else - mColumnWidthsLength = 5; - mColumnWidths = new PRInt32[mColumnWidthsLength]; - if (mColumnWidths) { - nsCRT::memset (mColumnWidths, 0, mColumnWidthsLength*sizeof(PRInt32)); - } -#endif + mBits.mHadInitialReflow = PR_FALSE; + mBits.mHaveReflowedColGroups = PR_FALSE; + mBits.mNeedStrategyInit = PR_TRUE; + mBits.mNeedStrategyBalance = PR_TRUE; + mBits.mCellSpansPctCol = PR_FALSE; + mBits.mRequestedTimeoutReflow = PR_FALSE; + #ifdef DEBUG_TABLE_REFLOW_TIMING mTimer = new nsReflowTimer(this); nsReflowTimer* timer = new nsReflowTimer(this); @@ -176,6 +197,10 @@ nsTableFrame::nsTableFrame() mTimer->mNextSibling->mNextSibling = timer; timer = new nsReflowTimer(this); mTimer->mNextSibling->mNextSibling->mNextSibling = timer; + timer = new nsReflowTimer(this); + mTimer->mNextSibling->mNextSibling->mNextSibling->mNextSibling = timer; + timer = new nsReflowTimer(this); + mTimer->mNextSibling->mNextSibling->mNextSibling->mNextSibling->mNextSibling = timer; #endif } @@ -225,10 +250,13 @@ nsTableFrame::Init(nsIPresContext* aPresContext, aPrevInFlow->GetSize(size); mRect.width = size.width; } - - if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && !mBorderCollapser) { - mBorderCollapser = new nsTableBorderCollapser(*this); - // if new fails then we don't get collapsing borders + else { + NS_ASSERTION(!mTableLayoutStrategy, "strategy was created before Init was called"); + nsCompatibility mode; + aPresContext->GetCompatibilityMode(&mode); + // create the strategy + mTableLayoutStrategy = (IsAutoLayout()) ? new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode) + : new FixedTableLayoutStrategy(this); } return rv; @@ -237,20 +265,11 @@ nsTableFrame::Init(nsIPresContext* aPresContext, nsTableFrame::~nsTableFrame() { - if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { - delete mBorderCollapser; - } - if (nsnull!=mCellMap) { delete mCellMap; mCellMap = nsnull; } - if (nsnull!=mColumnWidths) { - delete [] mColumnWidths; - mColumnWidths = nsnull; - } - if (nsnull!=mTableLayoutStrategy) { delete mTableLayoutStrategy; mTableLayoutStrategy = nsnull; @@ -267,6 +286,64 @@ nsTableFrame::Destroy(nsIPresContext* aPresContext) return nsHTMLContainerFrame::Destroy(aPresContext); } +NS_IMETHODIMP +nsTableFrame::ReflowCommandNotify(nsIPresShell* aShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded) + +{ + if (!aShell || !aRC) { + NS_ASSERTION(PR_FALSE, "invalid call to ReflowCommandNotify"); + return NS_ERROR_NULL_POINTER; + } + +#ifndef TABLE_REFLOW_COALESCING_OFF + nsIReflowCommand::ReflowType type; + aRC->GetType(type); + if ((type == nsIReflowCommand::ContentChanged) || + (type == nsIReflowCommand::StyleChanged) || + (type == nsIReflowCommand::ReflowDirty)) { + mNumDescendantReflowsPending += (aCommandAdded) ? 1 : -1; + } + else if (type == nsIReflowCommand::Timeout) { + if (aCommandAdded) { + mNumDescendantTimeoutReflowsPending++; + if (RequestedTimeoutReflow()) { + // since we can use the descendants timeout reflow, remove ours + aShell->CancelInterruptNotificationTo(this, nsIPresShell::Timeout); + SetRequestedTimeoutReflow(PR_FALSE); + } + } + else { + mNumDescendantTimeoutReflowsPending--; + if ((mNumDescendantTimeoutReflowsPending <= 0) && !RequestedTimeoutReflow() && + DescendantReflowedNotTimeout()) { + // a descendant caused us to cancel our timeout request but we really need one + aShell->SendInterruptNotificationTo(this, nsIPresShell::Timeout); + SetRequestedTimeoutReflow(PR_TRUE); + } + } + } +#endif + return NS_OK; +} + +void +nsTableFrame::InterruptNotification(nsIPresContext* aPresContext, + PRBool aIsRequest) +{ + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + if (aIsRequest) { + presShell->SendInterruptNotificationTo(this, nsIPresShell::Timeout); + SetRequestedTimeoutReflow(PR_TRUE); + } + else { + presShell->CancelInterruptNotificationTo(this, nsIPresShell::Timeout); + SetRequestedTimeoutReflow(PR_FALSE); + } +} + nscoord nsTableFrame::RoundToPixel(nscoord aValue, float aPixelToTwips) @@ -287,39 +364,57 @@ nsTableFrame::RoundToPixel(nscoord aValue, } } -// Helper function. It marks the table frame as dirty and generates -// a reflow command +// Helper function which marks aFrame as dirty and generates a reflow command nsresult -nsTableFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTableFrame) +nsTableFrame::AppendDirtyReflowCommand(nsIPresShell* aPresShell, + nsIFrame* aFrame) { - nsFrameState frameState; - nsIFrame* tableParentFrame; + if (!aPresShell) return NS_ERROR_NULL_POINTER; + + nsFrameState frameState; + aFrame->GetFrameState(&frameState); + + frameState |= NS_FRAME_IS_DIRTY; // mark the table frame as dirty + aFrame->SetFrameState(frameState); + nsIReflowCommand* reflowCmd; - nsresult rv; - nsIPresShell* presShell; - - aPresContext->GetShell(&presShell); - - // Mark the table frame as dirty - aTableFrame->GetFrameState(&frameState); - frameState |= NS_FRAME_IS_DIRTY; - aTableFrame->SetFrameState(frameState); - - // Target the reflow comamnd at its parent frame - aTableFrame->GetParent(&tableParentFrame); - rv = NS_NewHTMLReflowCommand(&reflowCmd, tableParentFrame, - nsIReflowCommand::ReflowDirty); + nsresult rv = NS_NewHTMLReflowCommand(&reflowCmd, aFrame, + nsIReflowCommand::ReflowDirty); if (NS_SUCCEEDED(rv)) { // Add the reflow command - rv = presShell->AppendReflowCommand(reflowCmd); + rv = aPresShell->AppendReflowCommand(reflowCmd); NS_RELEASE(reflowCmd); } - NS_RELEASE(presShell); return rv; } +// Make sure any views are positioned properlyvoid +void +nsTableFrame::RePositionViews(nsIPresContext* aPresContext, + nsIFrame* aFrame) +{ + nsIView* view; + aFrame->GetView(aPresContext, &view); + if (view) { + nsContainerFrame::PositionFrameView(aPresContext, aFrame, view); + } else { + nsContainerFrame::PositionChildViews(aPresContext, aFrame); + } +} + +nsIPresShell* +nsTableFrame::GetPresShellNoAddref(nsIPresContext* aPresContext) +{ + nsIPresShell* tempShell; + nsIPresShell* presShell; + aPresContext->GetShell(&tempShell); + presShell = tempShell; + NS_RELEASE(tempShell); // presShell is needed because this sets tempShell to nsnull + + return presShell; +} + // XXX this needs to be cleaned up so that the frame constructor breaks out col group // frames into a separate child list. NS_IMETHODIMP @@ -415,9 +510,10 @@ void nsTableFrame::AttributeChangedFor(nsIPresContext* aPresContext, nsVoidArray cells; cells.AppendElement(cellFrame); InsertCells(*aPresContext, cells, rowIndex, colIndex - 1); - // invalidate the column widths and generate a reflow command - InvalidateColumnWidths(); - AddTableDirtyReflowCommand(aPresContext, this); + + // XXX This could probably be optimized with some effort + SetNeedStrategyInit(PR_TRUE); + AppendDirtyReflowCommand(GetPresShellNoAddref(aPresContext), this); } } } @@ -478,7 +574,15 @@ PRInt32 nsTableFrame::GetEffectiveColCount () nsTableColFrame* nsTableFrame::GetColFrame(PRInt32 aColIndex) { - return (nsTableColFrame *)mColFrames.ElementAt(aColIndex); + NS_ASSERTION(!mPrevInFlow, "GetColFrame called on next in flow"); + PRInt32 numCols = mColFrames.Count(); + if ((aColIndex >= 0) && (aColIndex < numCols)) { + return (nsTableColFrame *)mColFrames.ElementAt(aColIndex); + } + else { + //NS_ASSERTION(PR_FALSE, "invalid col index"); + return nsnull; + } } // can return nsnull @@ -561,8 +665,7 @@ void nsTableFrame::ProcessGroupRules(nsIPresContext* aPresContext) if (nsLayoutAtoms::tableRowGroupFrame == frameType) { nsTableRowGroupFrame* rgFrame = (nsTableRowGroupFrame *)iFrame; PRInt32 startRow = rgFrame->GetStartRowIndex(); - PRInt32 numGroupRows; - rgFrame->GetRowCount(numGroupRows, PR_FALSE); + PRInt32 numGroupRows = rgFrame->GetRowCount(); PRInt32 endRow = startRow + numGroupRows - 1; if (startRow == endRow) { continue; @@ -618,22 +721,16 @@ NS_IMETHODIMP nsTableFrame::AdjustRowIndices(nsIPresContext* aPresContext, PRInt32 anAdjustment) { nsresult rv = NS_OK; - nsIFrame *rowFrame; + nsIFrame* rowFrame; aRowGroup->FirstChild(aPresContext, nsnull, &rowFrame); - for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(&rowFrame)) - { - const nsStyleDisplay *rowDisplay; + for ( ; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + const nsStyleDisplay* rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) { PRInt32 index = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); if (index >= aRowIndex) ((nsTableRowFrame *)rowFrame)->SetRowIndex(index+anAdjustment); } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) - { - AdjustRowIndices(aPresContext, rowFrame, aRowIndex, anAdjustment); - } } return rv; } @@ -737,14 +834,48 @@ void nsTableFrame::RemoveCol(nsIPresContext& aPresContext, /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ -nsTableCellMap * nsTableFrame::GetCellMap() const +nsTableCellMap* nsTableFrame::GetCellMap() const { - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - if (this!=firstInFlow) - { + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + if (this == firstInFlow) { + return mCellMap; + } + else { return firstInFlow->GetCellMap(); } - return mCellMap; +} + +nscoord nsTableFrame::GetMinWidth() const +{ + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + if (this == firstInFlow) { + return mMinWidth; + } + else { + return firstInFlow->GetMinWidth(); + } +} + +nscoord nsTableFrame::GetDesiredWidth() const +{ + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + if (this == firstInFlow) { + return mDesiredWidth; + } + else { + return firstInFlow->GetDesiredWidth(); + } +} + +inline nscoord nsTableFrame::GetPreferredWidth() const +{ + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + if (this == firstInFlow) { + return mPreferredWidth; + } + else { + return firstInFlow->GetPreferredWidth(); + } } // XXX this needs to be moved to nsCSSFrameConstructor @@ -891,7 +1022,6 @@ nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext, colFrame->Init(&aPresContext, iContent, &aColGroupFrame, styleContext, nsnull); colFrame->SetInitialChildList(&aPresContext, nsnull, nsnull); - ((nsTableColFrame *)colFrame)->SetType(aColType); // Add the col to the sibling chain if (lastColFrame) { @@ -916,7 +1046,7 @@ nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext, (nsIFrame*)&aColGroupFrame, aPrevFrameIn, nsLayoutAtoms::tableColFrame); if (colFrame) { - startColIndex = colFrame->GetColIndex(); + startColIndex = colFrame->GetColIndex() + 1; } } aColGroupFrame.AddColsToTable(aPresContext, startColIndex, PR_TRUE, @@ -1018,8 +1148,7 @@ nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame& aRowGroupFrame) if (rgFrame == &aRowGroupFrame) { break; } - PRInt32 numRows; - rgFrame->GetRowCount(numRows); + PRInt32 numRows = rgFrame->GetRowCount(); rowIndex += numRows; } return rowIndex; @@ -1094,16 +1223,35 @@ nsTableFrame::InsertRows(nsIPresContext& aPresContext, // this cannot extend beyond a single row group void nsTableFrame::RemoveRows(nsIPresContext& aPresContext, - PRInt32 aFirstRowIndex, + nsTableRowFrame& aFirstRowFrame, PRInt32 aNumRowsToRemove, PRBool aConsiderSpans) { //printf("removeRowsBefore firstRow=%d numRows=%d\n", aFirstRowIndex, aNumRowsToRemove); //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + +#ifdef TBD_OPTIMIZATION + // decide if we need to rebalance. we have to do this here because the row group + // cannot do it when it gets the dirty reflow corresponding to the frame being destroyed + PRBool stopTelling = PR_FALSE; + for (nsIFrame* kidFrame = aFirstFrame.FirstChild(); (kidFrame && !stopAsking); kidFrame = kidFrame->GetNextSibling()) { + nsCOMPtr kidType; + kidFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableCellFrame == kidType.get()) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*)kidFrame; + stopTelling = tableFrame->CellChangedWidth(*cellFrame, cellFrame->GetPass1MaxElementSize(), + cellFrame->GetMaximumWidth(), PR_TRUE); + } + } + // XXX need to consider what happens if there are cells that have rowspans + // into the deleted row. Need to consider moving rows if a rebalance doesn't happen +#endif + + PRInt32 firstRowIndex = aFirstRowFrame.GetRowIndex(); nsTableCellMap* cellMap = GetCellMap(); if (cellMap) { - cellMap->RemoveRows(&aPresContext, aFirstRowIndex, aNumRowsToRemove, aConsiderSpans); + cellMap->RemoveRows(&aPresContext, firstRowIndex, aNumRowsToRemove, aConsiderSpans); // only remove cols that are of type eTypeAnonymous cell (they are at the end) PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols PRInt32 numColsInCache = mColFrames.Count(); @@ -1113,7 +1261,7 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext, cellMap->AddColsAtEnd(numColsNotRemoved); } } - AdjustRowIndices(&aPresContext, aFirstRowIndex, -aNumRowsToRemove); + AdjustRowIndices(&aPresContext, firstRowIndex, -aNumRowsToRemove); //printf("removeRowsAfter\n"); //Dump(PR_TRUE, PR_FALSE, PR_TRUE); } @@ -1225,8 +1373,7 @@ nsTableFrame::InsertRowGroups(nsIPresContext& aPresContext, if (numRows > 0) { PRInt32 rowIndex = 0; if (priorRG) { - PRInt32 priorNumRows; - priorRG->GetRowCount(priorNumRows); + PRInt32 priorNumRows = priorRG->GetRowCount(); rowIndex = priorRG->GetStartRowIndex() + priorNumRows; } InsertRows(aPresContext, *rgFrame, rows, rowIndex, PR_TRUE); @@ -1240,48 +1387,6 @@ nsTableFrame::InsertRowGroups(nsIPresContext& aPresContext, } } -/* ***** Column Layout Data methods ***** */ - -/* - * Lists the column layout data which turns - * around and lists the cell layout data. - * This is for debugging purposes only. - */ -#ifdef NS_DEBUG -void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - if (this!=firstInFlow) - { - firstInFlow->ListColumnLayoutData(out, aIndent); - return; - } - - nsTableCellMap *cellMap = GetCellMap(); - if (nsnull!=cellMap) - { - fprintf(out,"Column Layout Data \n"); - - PRInt32 numCols = cellMap->GetColCount(); - PRInt32 numRows = cellMap->GetRowCount(); - for (PRInt32 colIndex = 0; colIndex= 0; ) - fputs(" ", out); - fprintf(out,"Column Data [%d] \n",colIndex); - for (PRInt32 rowIndex = 0; rowIndex < numRows; rowIndex++) - { -// nsTableCellFrame* cellFrame = cellMap->GetCellInfoAt(rowIndex, colIndex); - PRInt32 rowIndent; - for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out); - fprintf(out,"Cell Data [%d] \n",rowIndex); - for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out); - } - } - } -} -#endif - ///////////////////////////////////////////////////////////////////////////// // Child frame enumeration @@ -1350,20 +1455,12 @@ NS_METHOD nsTableFrame::Paint(nsIPresContext* aPresContext, } PRIntn skipSides = GetSkipSides(); - if (NS_STYLE_BORDER_SEPARATE == GetBorderCollapseStyle()) - { + if (NS_STYLE_BORDER_SEPARATE == GetBorderCollapseStyle()) { nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *border, mStyleContext, skipSides); } - else - { - //printf("paint table frame\n"); - nsBorderEdges* edges = nsnull; - if (mBorderCollapser) { - edges = mBorderCollapser->GetEdges(); - } - nsCSSRendering::PaintBorderEdges(aPresContext, aRenderingContext, this, - aDirtyRect, rect, edges, mStyleContext, skipSides); + else { + // tbd } } } @@ -1448,18 +1545,46 @@ nsTableFrame::GetSkipSides() const return skip; } +// this assumes that mNumDescendantReflowsPending and mNumDescendantTimeoutReflowsPending +// have already been updated for the current reflow PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) { PRBool result = PR_TRUE; - - if (mBits.mIsInvariantWidth) { - result = PR_FALSE; - } else if ((eReflowReason_Incremental == aReflowState.reason) && - (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) { - // If it's an incremental reflow and we're in galley mode, then only - // do a full reflow if we need to. We need to if the cell map is invalid, - // or the column info is invalid, or if we need to do a pass-1 reflow - result = !(IsFirstPassValid() && IsColumnWidthsValid()); + if ((eReflowReason_Incremental == aReflowState.reason) && + (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) { + // It's an incremental reflow and we're in galley mode. Only + // do a full reflow if we need to. +#ifndef TABLE_REFLOW_COALESCING_OFF + nsIFrame* reflowTarget; + aReflowState.reflowCommand->GetTarget(reflowTarget); + nsIReflowCommand::ReflowType reflowType; + aReflowState.reflowCommand->GetType(reflowType); + if (reflowType == nsIReflowCommand::Timeout) { + result = PR_FALSE; + if (this == reflowTarget) { + if (mNumDescendantTimeoutReflowsPending <= 0) { + // no more timeout reflows are coming targeted below + result = NeedStrategyInit() || NeedStrategyBalance(); + } + } + else if ((mNumDescendantTimeoutReflowsPending <= 0) && !RequestedTimeoutReflow()) { + // no more timeout reflows are coming targeted below or here + result = NeedStrategyInit() || NeedStrategyBalance(); + } + } + else { + if ((mNumDescendantTimeoutReflowsPending <= 0) && + !RequestedTimeoutReflow() && + (mNumDescendantReflowsPending <= 0)) { + // no more timeout reflows are coming targeted below or here, + // and no more normal reflows are coming targeted below + result = NeedStrategyInit() || NeedStrategyBalance(); + } + else result = PR_FALSE; + } +#else + result = NeedStrategyInit() || NeedStrategyBalance(); +#endif } return result; } @@ -1471,14 +1596,11 @@ PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) // // Slides all the row groups following aKidFrame by the specified // amount -// -// XXX This is kind of klunky because the InnerTableReflowState::y -// data member does not include the table's border/padding... -nsresult nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, - InnerTableReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize, - nscoord aDeltaY) +nsresult +nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsIFrame* aKidFrame, + nscoord aDeltaY) { NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight, "we're not in galley mode"); @@ -1511,25 +1633,12 @@ nsresult nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresCon // Adjust the running y-offset aReflowState.y += kidRect.height; - - // Update the max element size - //XXX: this should call into layout strategy to get the width field - if (aMaxElementSize) { - nsMargin borderPadding; - GetTableBorder (borderPadding); // gets the max border thickness for each edge - borderPadding += aReflowState.reflowState.mComputedPadding; - nscoord cellSpacing = GetCellSpacingX(); - nsSize kidMaxElementSize; - rgFrame->GetMaxElementSize(kidMaxElementSize); - nscoord kidWidth = kidMaxElementSize.width + borderPadding.left + borderPadding.right + cellSpacing*2; - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, kidWidth); - aMaxElementSize->height += kidMaxElementSize.height; - } - + // Adjust the y-origin if its position actually changed if (aDeltaY != 0) { kidRect.y += aDeltaY; kidFrame->MoveTo(aPresContext, kidRect.x, kidRect.y); + RePositionViews(aPresContext, kidFrame); } } @@ -1566,7 +1675,7 @@ nsTableFrame::SetColumnDimensions(nsIPresContext* aPresContext, colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { NS_ASSERTION(colX < numCols, "invalid number of columns"); - nscoord colWidth = mColumnWidths[colX]; + nscoord colWidth = GetColumnWidth(colX); nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(aPresContext, colRect); colOrigin.x += colWidth + cellSpacingX; @@ -1632,164 +1741,158 @@ nsTableFrame::GetParentStyleContextProvider(nsIPresContext* aPresContext, */ /* Layout the entire inner table. */ -NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, +NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason); #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); #endif - - // Initialize out parameter - if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = 0; - aDesiredSize.maxElementSize->height = 0; - } - aStatus = NS_FRAME_COMPLETE; - // XXX yank this nasty code and see what happens, and then yank other - // similar calls to InvalidateFirstPassCache. - if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) && - (this == (nsTableFrame *)GetFirstInFlow())) { - InvalidateFirstPassCache(); - } + aStatus = NS_FRAME_COMPLETE; + if (!mPrevInFlow && !mTableLayoutStrategy) { + NS_ASSERTION(PR_FALSE, "strategy should have been created in Init"); + return NS_ERROR_NULL_POINTER; + } nsresult rv = NS_OK; - nsSize* pass1MaxElementSize = aDesiredSize.maxElementSize; - if (eReflowReason_Incremental == aReflowState.reason) { - rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus); + PRBool isPaginated; + aPresContext->IsPaginated(&isPaginated); + + PRBool doCollapse = PR_FALSE; + + ComputePercentBasisForRows(aPresContext, aReflowState); + + aDesiredSize.width = aReflowState.availableWidth; + + nsReflowReason nextReason = aReflowState.reason; + + // The 1st reflow processes the needs of the reflow command + switch (aReflowState.reason) { + case eReflowReason_Initial: { + if (!HadInitialReflow()) { + // Check for an overflow list, and append any row group frames being pushed + MoveOverflowToChildList(aPresContext); + + if (IsAutoLayout()) { + // only do pass1 reflow on an auto layout table + nsTableReflowState reflowState(aReflowState, *this, eReflowReason_Initial, + NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); + // reflow the children + ReflowChildren(aPresContext, reflowState, !HaveReflowedColGroups(), PR_FALSE, aStatus); + } + if (!mPrevInFlow) { + mTableLayoutStrategy->Initialize(aPresContext, aReflowState); + } + } + else { // XXX put this back in when bug 70150 is fixed + // NS_ASSERTION(PR_FALSE, "intial reflow called twice"); + } + SetHadInitialReflow(PR_TRUE); + SetNeedStrategyBalance(PR_TRUE); // force a balance and then a pass2 reflow + nextReason = eReflowReason_Resize; + break; + } + case eReflowReason_Incremental: + NS_ASSERTION(HadInitialReflow(), "intial reflow not called"); + rv = IncrementalReflow(aPresContext, aReflowState, aStatus); + nextReason = eReflowReason_Resize; + break; + case eReflowReason_Resize: + // do the resize reflow below + NS_ASSERTION(HadInitialReflow(), "intial reflow not called"); + NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth, "this doesn't do anything"); + SetNeedStrategyBalance(PR_TRUE); + break; + case eReflowReason_StyleChange: + NS_ASSERTION(HadInitialReflow(), "intial reflow not called"); + SetNeedStrategyInit(PR_TRUE); // assume the worse + break; + default: + break; } - // If this is a style change reflow, then invalidate the pass 1 cache - if (eReflowReason_StyleChange == aReflowState.reason) { - InvalidateFirstPassCache(); - } + if (NS_FAILED(rv)) return rv; - // NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow - if (NeedsReflow(aReflowState)) { - PRBool needsRecalc = PR_FALSE; - if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) || - (PR_FALSE==IsFirstPassValid())) { - nsReflowReason reason = aReflowState.reason; - if ((eReflowReason_Initial != reason) && - (eReflowReason_StyleChange != reason)) { - reason = eReflowReason_Resize; + // The 2nd reflow is necessary during a constrained initial reflow and other reflows + // which require either a strategy init or balance. This isn't done during an + // unconstrained reflow because it is useless, and we will be reflowed again later. + if (NeedsReflow(aReflowState) && (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)) { + if (!mPrevInFlow) { + if (NeedStrategyInit()) { + mTableLayoutStrategy->Initialize(aPresContext, aReflowState); + BalanceColumnWidths(aPresContext, aReflowState); } - if (mBorderCollapser) { - mBorderCollapser->ComputeVerticalBorders(aPresContext, 0, -1); + if (NeedStrategyBalance()) { + BalanceColumnWidths(aPresContext, aReflowState); } - rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, reason, PR_TRUE); - if (NS_FAILED(rv)) - return rv; - needsRecalc = PR_TRUE; - } - if (mTableLayoutStrategy && (needsRecalc || !IsColumnWidthsValid())) { - nscoord boxWidth = CalcBorderBoxWidth(aReflowState); - mTableLayoutStrategy->Initialize(aPresContext, aDesiredSize.maxElementSize, - boxWidth, aReflowState); - mBits.mColumnWidthsValid = PR_TRUE; //so we don't do this a second time below } + // Constrain our reflow width to the computed table width (of the 1st in flow). + aDesiredSize.width = GetDesiredWidth(); + nsTableReflowState reflowState(aReflowState, *this, nextReason, + aDesiredSize.width, aReflowState.availableHeight); + ReflowChildren(aPresContext, reflowState, !HaveReflowedColGroups(), PR_FALSE, aStatus); - if (!mPrevInFlow) { - // only do this for a first-in-flow table frame - // assign column widths, and assign aMaxElementSize->width - BalanceColumnWidths(aPresContext, aReflowState, nsSize(aReflowState.availableWidth, aReflowState.availableHeight), - aDesiredSize.maxElementSize); + // If we're here that means we had to reflow all the rows, e.g., the column widths + // changed. We need to make sure that any damaged areas are repainted + Invalidate(aPresContext, mRect); - // assign table width - SetTableWidth(aPresContext, aReflowState); - } - - if ((eReflowReason_Initial == aReflowState.reason) && - (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth)) { - // Don't bother doing a pass2 reflow. Use our pass1 width as our - // desired width - aDesiredSize.width = mRect.width; - - } else { - // Constrain our reflow width to the computed table width. Note: this is based - // on the width of the first-in-flow - nsHTMLReflowState reflowState(aReflowState); - PRInt32 pass1Width = mRect.width; - if (mPrevInFlow) { - nsTableFrame* table = (nsTableFrame*)GetFirstInFlow(); - pass1Width = table->mRect.width; + if (eReflowReason_Resize == aReflowState.reason) { + if (isPaginated && (NS_FRAME_COMPLETE == aStatus) && (reflowState.availSize.height > 0)) { + // Try and pull-up some children from a next-in-flow + rv = PullUpChildren(aPresContext, aDesiredSize, reflowState, aStatus); } - reflowState.availableWidth = pass1Width; - if (pass1MaxElementSize) { - // we already have the max element size, so don't request it during pass2 - aDesiredSize.maxElementSize = nsnull; - } - rv = ResizeReflowPass2(aPresContext, aDesiredSize, reflowState, aStatus); - if (NS_FAILED(rv)) return rv; - - aDesiredSize.width = PR_MIN(aDesiredSize.width, pass1Width); - - // If this is an incremental reflow and we're here that means we had to - // reflow all the rows, e.g., the column widths changed. We need to make - // sure that any damaged areas are repainted - if (eReflowReason_Incremental == aReflowState.reason) { - nsRect damageRect; - - damageRect.x = 0; - damageRect.y = 0; - damageRect.width = mRect.width; - damageRect.height = mRect.height; - Invalidate(aPresContext, damageRect); + if (!DidResizeReflow()) { + // XXX we need to do this in other cases as well, but it needs to be made more incremental + doCollapse = PR_TRUE; + SetResizeReflow(PR_TRUE); } } } - else { - // set aDesiredSize and aMaxElementSize + + aDesiredSize.width = GetDesiredWidth(); + aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); + +#ifndef TABLE_REFLOW_COALESCING_OFF + // determine if we need to reset DescendantReflowedNotTimeout and/or + // RequestedTimeoutReflow after a timeout reflow. + if (aReflowState.reflowCommand) { + nsIReflowCommand::ReflowType type; + aReflowState.reflowCommand->GetType(type); + if (nsIReflowCommand::Timeout == type) { + nsIFrame* target = nsnull; + aReflowState.reflowCommand->GetTarget(target); + if (target == this) { // target is me + NS_ASSERTION(0 == mNumDescendantTimeoutReflowsPending, "was incorrectly target of timeout reflow"); + SetDescendantReflowedNotTimeout(PR_FALSE); + SetRequestedTimeoutReflow(PR_FALSE); + } + else if (target) { // target is descendant + if (0 >= mNumDescendantTimeoutReflowsPending) { + NS_ASSERTION(!RequestedTimeoutReflow(), "invalid timeout request"); + SetDescendantReflowedNotTimeout(PR_FALSE); + } + } + } } +#endif SetColumnDimensions(aPresContext, aDesiredSize.height, aReflowState.mComputedBorderPadding); - if (pass1MaxElementSize) { - aDesiredSize.maxElementSize = pass1MaxElementSize; + if (doCollapse) { + AdjustForCollapsingRows(aPresContext, aDesiredSize.height); + AdjustForCollapsingCols(aPresContext, aDesiredSize.width); } - // if we are reflowed unconstrained, update our preferred width - if (!mPrevInFlow && (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth)) { - SetPreferredWidth(aDesiredSize.width); + // See if we are supposed to return our max element size + if (aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = GetMinWidth(); + aDesiredSize.maxElementSize->height = 0; } - // See if we are supposed to compute our maximum width if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - PRBool isAutoOrPctWidth = IsAutoLayout() && - ((eStyleUnit_Auto == aReflowState.mStylePosition->mWidth.GetUnit() || - (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit()))); - - // See if the pass1 maximum width is no longer valid because one of the - // cell maximum widths changed - if (mPrevInFlow) { - // a next in flow just uses the preferred width of the 1st in flow. - nsTableFrame* firstInFlow = (nsTableFrame*)GetFirstInFlow(); - if (firstInFlow) { - aDesiredSize.mMaximumWidth = firstInFlow->GetPreferredWidth(); - } - } - else if (!IsMaximumWidthValid()) { - // Ask the strategy for the natural width of the content area - aDesiredSize.mMaximumWidth = mTableLayoutStrategy->GetTableMaxWidth(aReflowState); - - // Add in space for border - nsMargin border; - GetTableBorder (border); // this gets the max border value at every edge - aDesiredSize.mMaximumWidth += border.left + border.right; - - // Add in space for padding - aDesiredSize.mMaximumWidth += aReflowState.mComputedPadding.left + - aReflowState.mComputedPadding.right; - - // XXX to see if this is necessary - SetPreferredWidth(aDesiredSize.mMaximumWidth); // cache the value - - mBits.mMaximumWidthValid = PR_TRUE; - } else { - aDesiredSize.mMaximumWidth = GetPreferredWidth(); - } + aDesiredSize.mMaximumWidth = GetPreferredWidth(); } #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING @@ -1798,136 +1901,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, return rv; } -/** the first of 2 reflow passes - * lay out the captions and row groups in an infinite space (NS_UNCONSTRAINEDSIZE) - * cache the results for each caption and cell. - * if successful, set mFirstPassValid=PR_TRUE, so we know we can skip this step - * next time. mFirstPassValid is set to PR_FALSE when content is changed. - * NOTE: should never get called on a continuing frame! All cached pass1 state - * is stored in the inner table first-in-flow. - */ -NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus, - nsReflowReason aReason, - PRBool aDoSiblingFrames) -{ - NS_PRECONDITION(aReflowState.frame == this, "bad reflow state"); - NS_PRECONDITION(aReflowState.parentReflowState->frame == mParent, - "bad parent reflow state"); - NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame."); - NS_ASSERTION(nsnull != mContent, "null content"); - - nsresult rv = NS_OK; - // set out params - aStatus = NS_FRAME_COMPLETE; - - nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); // availSize is the space available at any given time in the process - nsSize maxSize(0, 0); // maxSize is the size of the largest child so far in the process - nsSize kidMaxSize(0,0); - nsHTMLReflowMetrics kidSize(&kidMaxSize); - nscoord y = 0; - nscoord cellSpacingY = GetCellSpacingY(); - - // Compute the insets (sum of border and padding) - // XXX: since this is pass1 reflow and where we place the rowgroup frames is irrelevant, insets are probably a waste - - if (IsAutoLayout()) { - nsVoidArray rowGroups; - PRUint32 numRowGroups; - OrderRowGroups(rowGroups, numRowGroups, nsnull); - PRUint32 numChildren = rowGroups.Count(); - - nsIFrame* kidFrame; - for (PRUint32 childX = 0; childX < numChildren; childX++) { - kidFrame = (nsIFrame*)rowGroups.ElementAt(childX); - if (childX >= numRowGroups) { - // it's an unknown frame type, give it a generic reflow and ignore the results - nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, - availSize, aReason); - // rv intentionally not set here - ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, aStatus); - kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - continue; - } - - // Get the table's border padding - nsMargin borderPadding; - GetTableBorderForRowGroup(GetRowGroupFrame(kidFrame), borderPadding); - const nsStylePadding* tablePadding; - GetStyleData(eStyleStruct_Padding, ((const nsStyleStruct *&)tablePadding)); - nsMargin padding; - tablePadding->GetPadding(padding); - borderPadding += padding; - - y += cellSpacingY; - if (0 == childX) { - y += borderPadding.top; - } - - // Reflow the child - nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, - availSize, aReason); - // Note: we don't bother checking here for whether we should clear the - // isTopOfPage reflow state flag, because we're dealing with an unconstrained - // height and it isn't an issue... - ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, borderPadding.left, - y, 0, aStatus); - - // Place the child since some of its content fit in us. - FinishReflowChild(kidFrame, aPresContext, kidSize, borderPadding.left, - borderPadding.top + y, 0); - if (NS_UNCONSTRAINEDSIZE == kidSize.height) - // XXX This is very suspicious. Why would a row group frame want - // such a large height? - y = NS_UNCONSTRAINEDSIZE; - else - y += kidSize.height; - if (kidMaxSize.width > maxSize.width) { - maxSize.width = kidMaxSize.width; - } - if (kidMaxSize.height > maxSize.height) { - maxSize.height = kidMaxSize.height; - } - - if (NS_FRAME_IS_NOT_COMPLETE(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). - break; - } - if (!aDoSiblingFrames) - break; - } - - // if required, give the colgroups their initial reflows - if (aDoSiblingFrames) { - kidFrame=mColGroups.FirstChild(); - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { - nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, - availSize, aReason); - ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, aStatus); - FinishReflowChild(kidFrame, aPresContext, kidSize, 0, 0, 0); - } - } - } - - // Get the table's border/padding - const nsStylePadding* myPadding = (const nsStylePadding*) - mStyleContext->GetStyleData(eStyleStruct_Padding); - nsMargin tableBorderPadding; - GetTableBorder (tableBorderPadding); // this gets the max border thickness at each edge - nsMargin tablePadding; - myPadding->GetPadding(tablePadding); - tableBorderPadding += tablePadding; - - aDesiredSize.width = kidSize.width; - nscoord defaultHeight = y + tableBorderPadding.top + tableBorderPadding.bottom; - aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState, defaultHeight); - mBits.mFirstPassValid = PR_TRUE; - - return rv; -} nsIFrame* nsTableFrame::GetFirstBodyRowGroupFrame() @@ -2022,7 +1995,7 @@ nsTableFrame::MoveOverflowToChildList(nsIPresContext* aPresContext) // Check for an overflow list with our prev-in-flow nsTableFrame* prevInFlow = (nsTableFrame*)mPrevInFlow; - if (nsnull != prevInFlow) { + if (prevInFlow) { nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); if (prevOverflowFrames) { // When pushing and pulling frames we need to check for whether any @@ -2044,73 +2017,6 @@ nsTableFrame::MoveOverflowToChildList(nsIPresContext* aPresContext) return result; } -/** the second of 2 reflow passes - */ -NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == this, "bad reflow state"); - NS_PRECONDITION(aReflowState.parentReflowState->frame == mParent, - "bad parent reflow state"); - nsresult rv = NS_OK; - // set out param - aStatus = NS_FRAME_COMPLETE; - - nsMargin borderPadding; - GetTableBorder (borderPadding); // this gets the max border thickness at each edge - borderPadding += aReflowState.mComputedPadding; - - InnerTableReflowState state(aPresContext, aReflowState, borderPadding); - state.y = borderPadding.top; // XXX this should be set in the constructor, but incremental code is affected. - // now that we've computed the column width information, reflow all children - -#ifdef NS_DEBUG - //PreReflowCheck(); -#endif - - // Check for an overflow list, and append any row group frames being - // pushed - MoveOverflowToChildList(aPresContext); - - // Reflow the existing frames - if (mFrames.NotEmpty()) { - ComputePercentBasisForRows(aPresContext, aReflowState); - rv = ReflowMappedChildren(aPresContext, aDesiredSize, state, aStatus); - } - - // Did we successfully reflow our mapped children? - if (NS_FRAME_COMPLETE == aStatus) { - // Any space left? - if (state.availSize.height > 0) { - // Try and pull-up some children from a next-in-flow - rv = PullUpChildren(aPresContext, aDesiredSize, state, aStatus); - } - } - - // Return our size and our status - aDesiredSize.width = ComputeDesiredWidth(aReflowState); - nscoord defaultHeight = state.y + GetCellSpacingY() + borderPadding.bottom; - aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState, defaultHeight); - - AdjustForCollapsingRows(aPresContext, aDesiredSize.height); - AdjustForCollapsingCols(aPresContext, aDesiredSize.width); - - // once horizontal borders are computed and all row heights are set, - // we need to fix up length of vertical edges - // XXX need to figure start row and end row correctly - if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { - mBorderCollapser->DidComputeHorizontalBorders(aPresContext, 0, 10000); - } - -#ifdef NS_DEBUG - //PostReflowCheck(aStatus); -#endif - - return rv; - -} void nsTableFrame::ComputePercentBasisForRows(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) @@ -2145,10 +2051,7 @@ nsTableFrame::CollapseRowGroupIfNecessary(nsIPresContext* aPresContext, while (nsnull != rowFrame) { const nsStyleDisplay* rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { - CollapseRowGroupIfNecessary(aPresContext, rowFrame, aYTotalOffset, aYGroupOffset, aRowX); - } - else if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { nsRect rowRect; rowFrame->GetRect(rowRect); if (collapseGroup || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { @@ -2392,25 +2295,8 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, InsertColGroups(*aPresContext, startColIndex, firstAppendedColGroup); } - // We'll need to do a pass-1 layout of all cells in all the rows of the - // rowgroup. XXX - fix this - InvalidateFirstPassCache(); - - // Because the number of columns may have changed invalidate them - InvalidateColumnWidths(); - - // Mark the table as dirty and generate a reflow command targeted at the - // outer table frame - nsIReflowCommand* reflowCmd; - nsresult rv; - - mState |= NS_FRAME_IS_DIRTY; - rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - // Add the reflow command - rv = aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } + SetNeedStrategyInit(PR_TRUE); // XXX assume the worse + AppendDirtyReflowCommand(&aPresShell, this); return NS_OK; } @@ -2451,6 +2337,7 @@ nsTableFrame::InsertFrames(nsIPresContext* aPresContext, } } InsertColGroups(*aPresContext, startColIndex, aFrameList, lastFrame); + SetNeedStrategyInit(PR_TRUE); } else if (IsRowGroup(display->mDisplay)) { // get the starting row index of the new rows and insert them into the table PRInt32 rowIndex = 0; @@ -2466,30 +2353,14 @@ nsTableFrame::InsertFrames(nsIPresContext* aPresContext, mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList); InsertRowGroups(*aPresContext, aFrameList, lastSibling); + SetNeedStrategyInit(PR_TRUE); } else { // Just insert the frame and don't worry about reflowing it mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList); return NS_OK; } - // Because the number of columns may have changed invalidate them - InvalidateColumnWidths(); - - InvalidateFirstPassCache(); // XXX fix this - - // Mark the table as dirty and generate a reflow command targeted at the - // outer table frame - nsIReflowCommand* reflowCmd; - nsresult rv; - - mState |= NS_FRAME_IS_DIRTY; - rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - // Add the reflow command - rv = aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - return rv; + AppendDirtyReflowCommand(&aPresShell, this); return NS_OK; } @@ -2522,12 +2393,6 @@ nsTableFrame::RemoveFrame(nsIPresContext* aPresContext, RemoveCol(*aPresContext, colGroup, colX, PR_TRUE, PR_FALSE); } } - for (colX = lastColIndex; colX >= firstColIndex; colX--) { - nsTableColFrame* colFrame = (nsTableColFrame*)mColFrames.ElementAt(colX); - if (colFrame) { - RemoveCol(*aPresContext, colGroup, colX, PR_FALSE, PR_TRUE); - } - } PRInt32 numAnonymousColsToAdd = GetColCount() - mColFrames.Count(); if (numAnonymousColsToAdd > 0) { @@ -2536,14 +2401,14 @@ nsTableFrame::RemoveFrame(nsIPresContext* aPresContext, eColAnonymousCell, PR_TRUE); } - InvalidateColumnWidths(); - AddTableDirtyReflowCommand(aPresContext, this); + // XXX This could probably be optimized with much effort + SetNeedStrategyInit(PR_TRUE); + AppendDirtyReflowCommand(GetPresShellNoAddref(aPresContext), this); } else { nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aOldFrame); if (rgFrame) { PRInt32 startRowIndex = rgFrame->GetStartRowIndex(); - PRInt32 numRows; - rgFrame->GetRowCount(numRows, PR_TRUE); + PRInt32 numRows = rgFrame->GetRowCount(); // remove the row group from the cell map nsTableCellMap* cellMap = GetCellMap(); if (cellMap) { @@ -2561,8 +2426,9 @@ nsTableFrame::RemoveFrame(nsIPresContext* aPresContext, // remove the row group frame from the sibling chain mFrames.DestroyFrame(aPresContext, aOldFrame); - InvalidateColumnWidths(); - AddTableDirtyReflowCommand(aPresContext, this); + // XXX This could probably be optimized with much effort + SetNeedStrategyInit(PR_TRUE); + AppendDirtyReflowCommand(GetPresShellNoAddref(aPresContext), this); } else { // Just remove the frame mFrames.DestroyFrame(aPresContext, aOldFrame); @@ -2572,161 +2438,120 @@ nsTableFrame::RemoveFrame(nsIPresContext* aPresContext, return NS_OK; } -NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableFrame::IncrementalReflow(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; // Constrain our reflow width to the computed table width. Note: this is // based on the width of the first-in-flow - nsHTMLReflowState reflowState(aReflowState); - PRInt32 pass1Width = mRect.width; + PRInt32 lastWidth = mRect.width; if (mPrevInFlow) { nsTableFrame* table = (nsTableFrame*)GetFirstInFlow(); - pass1Width = table->mRect.width; + lastWidth = table->mRect.width; } - reflowState.availableWidth = pass1Width; - - // get border + padding - nsMargin borderPadding; - GetTableBorder (borderPadding); - borderPadding += aReflowState.mComputedPadding; - - InnerTableReflowState state(aPresContext, reflowState, borderPadding); + nsTableReflowState state(aReflowState, *this, eReflowReason_Incremental, + lastWidth, aReflowState.availableHeight); // determine if this frame is the target or not - nsIFrame *target=nsnull; - rv = reflowState.reflowCommand->GetTarget(target); - if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target)) - { + nsIFrame* target = nsnull; + rv = aReflowState.reflowCommand->GetTarget(target); + if (NS_SUCCEEDED(rv) && target) { + nsIReflowCommand::ReflowType type; + aReflowState.reflowCommand->GetType(type); // this is the target if target is either this or the outer table frame containing this inner frame - nsIFrame *outerTableFrame=nsnull; + nsIFrame* outerTableFrame = nsnull; GetParent(&outerTableFrame); - if ((this==target) || (outerTableFrame==target)) - rv = IR_TargetIsMe(aPresContext, aDesiredSize, state, aStatus); - else - { + if ((this == target) || (outerTableFrame == target)) { + rv = IR_TargetIsMe(aPresContext, state, aStatus); + } + else { // Get the next frame in the reflow chain nsIFrame* nextFrame; - reflowState.reflowCommand->GetNext(nextFrame); + aReflowState.reflowCommand->GetNext(nextFrame); NS_ASSERTION(nextFrame, "next frame in reflow command is null"); - - // Recover our reflow state - rv = IR_TargetIsChild(aPresContext, aDesiredSize, state, aStatus, nextFrame); + rv = IR_TargetIsChild(aPresContext, state, aStatus, nextFrame); } } return rv; } -// this assumes the dirty children are contiguous -// XXX if this is ever used again, it probably needs to call OrderRowGroups -PRBool GetDirtyChildren(nsIPresContext* aPresContext, - nsIFrame* aFrame, - nsIFrame** aFirstDirty, - PRInt32& aNumDirty) -{ - *aFirstDirty = nsnull; - aNumDirty = 0; - - nsIFrame* kidFrame; - aFrame->FirstChild(aPresContext, nsnull, &kidFrame); - while (kidFrame) { - nsFrameState frameState; - kidFrame->GetFrameState(&frameState); - if (frameState & NS_FRAME_IS_DIRTY) { - if (!*aFirstDirty) { - *aFirstDirty = kidFrame; - } - aNumDirty++; - } - } - return (aNumDirty > 0); -} - -NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; aStatus = NS_FRAME_COMPLETE; + nsIReflowCommand::ReflowType type; aReflowState.reflowState.reflowCommand->GetType(type); - nsIFrame *objectFrame; - aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame); - const nsStyleDisplay *childDisplay=nsnull; - if (nsnull!=objectFrame) - objectFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - switch (type) - { - case nsIReflowCommand::StyleChanged : - rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); - break; - case nsIReflowCommand::ContentChanged : - NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - - case nsIReflowCommand::ReflowDirty: - { - //nsIFrame* dirtyChild; - //PRInt32 numDirty; - //if (GetDirtyChildren(this, &dirtyChild, numDirty)) { - // for (PRInt32 dirtyX = 0; dirtyX < numDirty; dirtyX++) { - // ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, - // dirtyChild, reason, PR_FALSE); - // dirtyChild->GetNextSibling(&dirtyChild); - // } - //} - //else { - // Problem is we don't know has changed, so assume the worst - InvalidateFirstPassCache(); - //} - InvalidateColumnWidths(); - rv = NS_OK; + switch (type) { + case nsIReflowCommand::StyleChanged : + rv = IR_StyleChanged(aPresContext, aReflowState, aStatus); + break; + case nsIReflowCommand::ContentChanged : + NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + case nsIReflowCommand::ReflowDirty: { + // reflow the dirty children + nsTableReflowState reflowState(aReflowState.reflowState, *this, eReflowReason_Initial, + aReflowState.availSize.width, aReflowState.availSize.height); + PRBool reflowedAtLeastOne; + ReflowChildren(aPresContext, reflowState, PR_FALSE, PR_TRUE, aStatus, &reflowedAtLeastOne); + if (!reflowedAtLeastOne) + // XXX For now assume the worse + SetNeedStrategyInit(PR_TRUE); + } + break; + case nsIReflowCommand::Timeout: { + // for a timeout reflow, don't do anything here break; } - - default: - NS_NOTYETIMPLEMENTED("unexpected reflow command type"); - rv = NS_ERROR_NOT_IMPLEMENTED; - break; + default: + NS_NOTYETIMPLEMENTED("unexpected reflow command type"); + rv = NS_ERROR_NOT_IMPLEMENTED; + break; } return rv; } -NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus) { - nsresult rv = NS_OK; - // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here - // XXX: we can optimize this when we know which style attribute changed - // if something like border changes, we need to do pass1 again - // but if something like width changes from 100 to 200, we just need to do pass2 - InvalidateFirstPassCache(); - return rv; + // we presume that all the easy optimizations were done in the nsHTMLStyleSheet + // before we were called here + SetNeedStrategyInit(PR_TRUE); + return NS_OK; } -// Recovers the reflow state to what it should be if aKidFrame is about -// to be reflowed. Restores the following: -// - availSize -// - y -// - footerFrame -// - firstBodySection -// -// XXX This is kind of klunky because the InnerTableReflowState::y -// data member does not include the table's border/padding... -nsresult -nsTableFrame::RecoverState(InnerTableReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize) +nsMargin +nsTableFrame::GetBorderPadding(const nsHTMLReflowState& aReflowState) const { + const nsStyleBorder* border = + (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border); + nsMargin borderPadding; + border->GetBorder(borderPadding); + borderPadding += aReflowState.mComputedPadding; + return borderPadding; +} + +// Recovers the reflow state to what it should be if aKidFrame is about to be +// reflowed. Restores y, footerFrame, firstBodySection and availSize.height (if +// the height is constrained) +nsresult +nsTableFrame::RecoverState(nsTableReflowState& aReflowState, + nsIFrame* aKidFrame) +{ + nsMargin borderPadding = GetBorderPadding(aReflowState.reflowState); + aReflowState.y = borderPadding.top; + nscoord cellSpacingY = GetCellSpacingY(); // Get the ordered children and find aKidFrame in the list nsVoidArray rowGroups; @@ -2740,7 +2565,7 @@ nsTableFrame::RecoverState(InnerTableReflowState& aReflowState, if (!rgFrame) continue; // skip foreign frame types // If this is a footer row group, remember it - const nsStyleDisplay *display; + const nsStyleDisplay* display; rgFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); // We only allow a single footer frame @@ -2767,7 +2592,7 @@ nsTableFrame::RecoverState(InnerTableReflowState& aReflowState, // If our height is constrained then update the available height. Do // this for all frames including the footer frame - if (PR_FALSE == aReflowState.unconstrainedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) { aReflowState.availSize.height -= kidSize.height; } @@ -2775,80 +2600,78 @@ nsTableFrame::RecoverState(InnerTableReflowState& aReflowState, if (childFrame != aReflowState.footerFrame) { aReflowState.y += kidSize.height; } - - // Update the max element size - //XXX: this should call into layout strategy to get the width field - if (nsnull != aMaxElementSize) - { - nsMargin borderPadding; - GetTableBorder (borderPadding); // gets the max border thickness for each edge - borderPadding += aReflowState.reflowState.mComputedPadding; - nscoord cellSpacing = GetCellSpacingX(); - nsSize kidMaxElementSize; - rgFrame->GetMaxElementSize(kidMaxElementSize); - nscoord kidWidth = kidMaxElementSize.width + borderPadding.left + borderPadding.right + cellSpacing*2; - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, kidWidth); - aMaxElementSize->height += kidMaxElementSize.height; - } } return NS_OK; } -NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame) +NS_METHOD +nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame) { nsresult rv; // Recover the state as if aNextFrame is about to be reflowed - RecoverState(aReflowState, aNextFrame, aDesiredSize.maxElementSize); + RecoverState(aReflowState, aNextFrame); // Remember the old rect nsRect oldKidRect; aNextFrame->GetRect(oldKidRect); - // Pass along the reflow command - nsSize kidMaxElementSize; - nsHTMLReflowMetrics desiredSize(aDesiredSize.maxElementSize ? &kidMaxElementSize : nsnull, - aDesiredSize.mFlags); + // Pass along the reflow command, don't request a max element size, rows will do that + nsHTMLReflowMetrics desiredSize(nsnull); nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame, aReflowState.availSize); - nscoord x = aReflowState.mBorderPadding.left; - nscoord y = aReflowState.mBorderPadding.top + aReflowState.y; rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, - x, y, 0, aStatus); + aReflowState.x, aReflowState.y, 0, aStatus); // Place the row group frame. Don't use PlaceChild(), because it moves // the footer frame as well. We'll adjust the footer frame later on in // AdjustSiblingsAfterReflow() - nsRect kidRect(x, y, desiredSize.width, desiredSize.height); - FinishReflowChild(aNextFrame, aPresContext, desiredSize, x, y, 0); + nsRect kidRect(aReflowState.x, aReflowState.y, desiredSize.width, desiredSize.height); + FinishReflowChild(aNextFrame, aPresContext, desiredSize, aReflowState.x, aReflowState.y, 0); + +#ifndef TABLE_REFLOW_COALESCING_OFF + // update the descendant reflow counts and determine if we need to request a timeout reflow + PRBool needToRequestTimeoutReflow = PR_FALSE; + nsIReflowCommand::ReflowType type; + aReflowState.reflowState.reflowCommand->GetType(type); + if (nsIReflowCommand::Timeout == type) { + mNumDescendantTimeoutReflowsPending--; + NS_ASSERTION(mNumDescendantTimeoutReflowsPending >= 0, "invalid descendant reflow count"); + } + else { + mNumDescendantReflowsPending--; + NS_ASSERTION(mNumDescendantReflowsPending >= 0, "invalid descendant reflow count"); + SetDescendantReflowedNotTimeout(PR_TRUE); + // request a timeout reflow if there are no more timeout reflows coming, more normal + // reflows are coming, and we haven't already requested one. + if ((mNumDescendantTimeoutReflowsPending <= 0) && + (mNumDescendantReflowsPending > 0) && + !RequestedTimeoutReflow()) { + InterruptNotification(aPresContext, PR_TRUE); + } + // cancel our timeout reflow (if present) if there are no more coming and + // this is the last child to be reflowed. + else if ((mNumDescendantTimeoutReflowsPending <= 0) && + (mNumDescendantReflowsPending <= 0) && + RequestedTimeoutReflow()) { + InterruptNotification(aPresContext, PR_FALSE); + } + } +#endif // Adjust the running y-offset aReflowState.y += desiredSize.height + GetCellSpacingY(); // If our height is constrained, then update the available height - if (PR_FALSE == aReflowState.unconstrainedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) { aReflowState.availSize.height -= desiredSize.height; } - // Update the max element size - //XXX: this should call into layout strategy to get the width field - if (nsnull != aDesiredSize.maxElementSize) - { - nsMargin borderPadding; - GetTableBorder (borderPadding); // gets the max border thickness for each edge - borderPadding += aReflowState.reflowState.mComputedPadding; - nscoord cellSpacing = GetCellSpacingX(); - nscoord kidWidth = kidMaxElementSize.width + borderPadding.left + borderPadding.right + cellSpacing*2; - aDesiredSize.maxElementSize->width = PR_MAX(aDesiredSize.maxElementSize->width, kidWidth); - aDesiredSize.maxElementSize->height += kidMaxElementSize.height; - } - // If the column width info is valid, then adjust the row group frames // that follow. Otherwise, return and we'll recompute the column widths // and reflow all the row group frames @@ -2856,81 +2679,43 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // If the row group frame changed height, then damage the horizontal strip // that was either added or went away if (desiredSize.height != oldKidRect.height) { - nsRect dirtyRect; - + nsRect dirtyRect; dirtyRect.x = 0; dirtyRect.y = PR_MIN(oldKidRect.YMost(), kidRect.YMost()); dirtyRect.width = mRect.width; - dirtyRect.height = PR_MAX(oldKidRect.YMost(), kidRect.YMost()) - - dirtyRect.y; + dirtyRect.height = PR_MAX(oldKidRect.YMost(), kidRect.YMost()) - dirtyRect.y; Invalidate(aPresContext, dirtyRect); } // Adjust the row groups that follow - AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, - aDesiredSize.maxElementSize, desiredSize.height - - oldKidRect.height); - - // Return our size and our status - aDesiredSize.width = ComputeDesiredWidth(aReflowState.reflowState); - nscoord defaultHeight = aReflowState.y + aReflowState.mBorderPadding.top + - aReflowState.mBorderPadding.bottom; - aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState.reflowState, - defaultHeight); + AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, + desiredSize.height - oldKidRect.height); // XXX Is this needed? #if 0 AdjustForCollapsingRows(aPresContext, aDesiredSize.height); AdjustForCollapsingCols(aPresContext, aDesiredSize.width); - - // once horizontal borders are computed and all row heights are set, - // we need to fix up length of vertical edges - // XXX need to figure start row and end row correctly - if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { - mBorderCollapser->DidComputeHorizontalBorders(aPresContext, 0, 10000); - } #endif } return rv; } -nscoord nsTableFrame::ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) const -{ - nscoord desiredWidth = aReflowState.availableWidth; - if (NS_UNCONSTRAINEDSIZE == desiredWidth) { - // XXX this code path is not used, but if it is needed, then borders and padding must be added - NS_ASSERTION(PR_FALSE, "code path in ComputeDesiredWidth is not complete"); - nsITableLayoutStrategy* tableLayoutStrategy = mTableLayoutStrategy; - if (mPrevInFlow) { - // Get the table layout strategy from the first-in-flow - nsTableFrame* table = (nsTableFrame*)GetFirstInFlow(); - tableLayoutStrategy = table->mTableLayoutStrategy; - } - desiredWidth = tableLayoutStrategy->GetTableMaxWidth(aReflowState); - } - return desiredWidth; -} - // Position and size aKidFrame and update our reflow state. The origin of // aKidRect is relative to the upper-left origin of our frame -void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, - InnerTableReflowState& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize, - nscoord aX, - nscoord aY, - nsSize* aMaxElementSize, - nsSize& aKidMaxElementSize) +void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsIFrame* aKidFrame, + nsHTMLReflowMetrics& aDesiredSize) { // Place and size the child - FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, aX, aY, 0); + FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, aReflowState.x, aReflowState.y, 0); // Adjust the running y-offset aReflowState.y += aDesiredSize.height; // If our height is constrained, then update the available height - if (PR_FALSE == aReflowState.unconstrainedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) { aReflowState.availSize.height -= aDesiredSize.height; } @@ -2955,17 +2740,6 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, origin.y = aReflowState.y - size.height; aReflowState.footerFrame->MoveTo(aPresContext, origin.x, origin.y); } - - //XXX: this should call into layout strategy to get the width field - if (nsnull != aMaxElementSize) { - nsMargin borderPadding; - GetTableBorder (borderPadding); // gets the max border thickness for each edge - borderPadding += aReflowState.reflowState.mComputedPadding; - nscoord cellSpacing = GetCellSpacingX(); - nscoord kidWidth = aKidMaxElementSize.width + borderPadding.left + borderPadding.right + cellSpacing*2; - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, kidWidth); - aMaxElementSize->height += aKidMaxElementSize.height; - } } void @@ -3034,171 +2808,171 @@ nsTableFrame::OrderRowGroups(nsVoidArray& aChildren, } } -/** - * Reflow the frames we've already created - * - * @param aPresContext presentation context to use - * @param aReflowState 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 - */ -NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus) +// Reflow the children based on the avail size and reason in aReflowState +// update aReflowMetrics a aStatus +NS_METHOD +nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + PRBool aDoColGroups, + PRBool aDirtyOnly, + nsReflowStatus& aStatus, + PRBool* aReflowedAtLeastOne) { - NS_PRECONDITION(mFrames.NotEmpty(), "no children"); + aStatus = NS_FRAME_COMPLETE; nsIFrame* prevKidFrame = nsnull; - nsSize kidMaxElementSize(0,0); - nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; nsresult rv = NS_OK; nscoord cellSpacingY = GetCellSpacingY(); - nsReflowReason reason; - if (!IsAutoLayout()) { - reason = aReflowState.reflowState.reason; - if (eReflowReason_Incremental==reason) { - reason = eReflowReason_Resize; - if (aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = 0; - aDesiredSize.maxElementSize->height = 0; - } - } - } - else { - reason = eReflowReason_Resize; - } - - // this never passes reflows down to colgroups nsVoidArray rowGroups; PRUint32 numRowGroups; OrderRowGroups(rowGroups, numRowGroups, &aReflowState.firstBodySection); + PRBool haveReflowedRowGroup = PR_FALSE; for (PRUint32 childX = 0; ((PRInt32)childX) < rowGroups.Count(); childX++) { nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(childX); - nsSize kidAvailSize(aReflowState.availSize); - nsHTMLReflowMetrics desiredSize(pKidMaxElementSize); - desiredSize.width = desiredSize.height = desiredSize.ascent = desiredSize.descent = 0; + // Get the frame state bits + nsFrameState frameState; + kidFrame->GetFrameState(&frameState); - PRBool didFirstBody = PR_FALSE; - if (childX < numRowGroups) { - // Keep track of the first body section row group - if (kidFrame == aReflowState.firstBodySection) { - didFirstBody = PR_TRUE; - } + // See if we should only reflow the dirty child frames + PRBool doReflowChild = PR_TRUE; + if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) { + doReflowChild = PR_FALSE; + } - nsMargin borderPadding; - GetTableBorderForRowGroup(GetRowGroupFrame(kidFrame), borderPadding); - borderPadding += aReflowState.reflowState.mComputedPadding; - - // Reflow the child into the available space - nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, - kidFrame, kidAvailSize, reason); - // XXX fix up bad mComputedWidth for scroll frame - kidReflowState.mComputedWidth = PR_MAX(kidReflowState.mComputedWidth, 0); - - if (didFirstBody && (kidFrame != aReflowState.firstBodySection)) { - // If this isn't the first row group frame or the header or footer, then - // we can't be at the top of the page anymore... - kidReflowState.isTopOfPage = PR_FALSE; - } - - aReflowState.y += cellSpacingY; - nscoord x = borderPadding.left; - nscoord y = aReflowState.y; - - if (RowGroupsShouldBeConstrained()) { - // Only applies to the tree widget. - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState.reflowState); - if ((tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { - kidReflowState.availableHeight = tableSpecifiedHeight - y; - if (kidReflowState.availableHeight < 0) - kidReflowState.availableHeight = 0; + if (doReflowChild) { + nsSize kidAvailSize(aReflowState.availSize); + nsHTMLReflowMetrics desiredSize(nsnull); + desiredSize.width = desiredSize.height = desiredSize.ascent = desiredSize.descent = 0; + + PRBool didFirstBody = PR_FALSE; + if (childX < numRowGroups) { + // Keep track of the first body section row group + if (kidFrame == aReflowState.firstBodySection) { + didFirstBody = PR_TRUE; } - } + + // Reflow the child into the available space + nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, + kidFrame, kidAvailSize, aReflowState.reason); + // XXX fix up bad mComputedWidth for scroll frame + kidReflowState.mComputedWidth = PR_MAX(kidReflowState.mComputedWidth, 0); + + if (didFirstBody && (kidFrame != aReflowState.firstBodySection)) { + // If this isn't the first row group frame or the header or footer, then + // we can't be at the top of the page anymore... + kidReflowState.isTopOfPage = PR_FALSE; + } + + aReflowState.y += cellSpacingY; + + // record the next in flow in case it gets destroyed and the row group array + // needs to be recomputed. + nsIFrame* kidNextInFlow; + kidFrame->GetNextInFlow(&kidNextInFlow); + + rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, + aReflowState.x, aReflowState.y, 0, aStatus); + haveReflowedRowGroup = PR_TRUE; - // record the next in flow in case it gets destroyed and the row group array - // needs to be recomputed. - nsIFrame* kidNextInFlow; - kidFrame->GetNextInFlow(&kidNextInFlow); - - rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - x, y, 0, aStatus); - // Did the child fit? - if (desiredSize.height > kidAvailSize.height) { - if (aReflowState.firstBodySection && (kidFrame != aReflowState.firstBodySection)) { - // The child is too tall to fit at all in the available space, and it's - // not a header/footer or our first row group frame - PushChildren(aPresContext, kidFrame, prevKidFrame); - aStatus = NS_FRAME_NOT_COMPLETE; + // Did the child fit? + if (desiredSize.height > kidAvailSize.height) { + if (aReflowState.firstBodySection && (kidFrame != aReflowState.firstBodySection)) { + // The child is too tall to fit at all in the available space, and it's + // not a header/footer or our first row group frame + PushChildren(aPresContext, kidFrame, prevKidFrame); + aStatus = NS_FRAME_NOT_COMPLETE; + break; + } + } + + // Place the child + PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize); + + // Remember where we just were in case we end up pushing children + prevKidFrame = kidFrame; + + // Special handling for incomplete children + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + kidFrame->GetNextInFlow(&kidNextInFlow); + if (!kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame; + nsIPresShell* presShell; + nsIStyleSet* styleSet; + + aPresContext->GetShell(&presShell); + presShell->GetStyleSet(&styleSet); + NS_RELEASE(presShell); + styleSet->CreateContinuingFrame(aPresContext, kidFrame, this, &continuingFrame); + NS_RELEASE(styleSet); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib; + + kidFrame->GetNextSibling(&nextSib); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + } + // 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(aPresContext, nextSibling, kidFrame); + } break; } - } - - // Place the child - // we don't want to adjust the maxElementSize if this is an initial reflow - // it was set by the TableLayoutStrategy and shouldn't be changed. - nsSize* requestedMaxElementSize = nsnull; - if (eReflowReason_Initial != aReflowState.reflowState.reason) - requestedMaxElementSize = aDesiredSize.maxElementSize; - PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - x, y, requestedMaxElementSize, kidMaxElementSize); - - // Remember where we just were in case we end up pushing children - prevKidFrame = kidFrame; - - // Special handling for incomplete children - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - kidFrame->GetNextInFlow(&kidNextInFlow); - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a continuing - // frame. This hooks the child into the flow - nsIFrame* continuingFrame; - nsIPresShell* presShell; - nsIStyleSet* styleSet; - - aPresContext->GetShell(&presShell); - presShell->GetStyleSet(&styleSet); - NS_RELEASE(presShell); - styleSet->CreateContinuingFrame(aPresContext, kidFrame, this, &continuingFrame); - NS_RELEASE(styleSet); - - // Add the continuing frame to the sibling list - nsIFrame* nextSib; - - kidFrame->GetNextSibling(&nextSib); - continuingFrame->SetNextSibling(nextSib); - kidFrame->SetNextSibling(continuingFrame); + else if (kidNextInFlow) { + // during printing, the unfortunate situation arises where a next in flow can be a + // next sibling and the next sibling can get destroyed during the reflow. By reordering + // the row groups, the rowGroups array can be kept in sync. + OrderRowGroups(rowGroups, numRowGroups, nsnull); } - // 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(aPresContext, nextSibling, kidFrame); - } - break; } - else if (kidNextInFlow) { - // during printing, the unfortunate situation arises where a next in flow can be a - // next sibling and the next sibling can get destroyed during the reflow. By reordering - // the row groups, the rowGroups array can be kept in sync. - OrderRowGroups(rowGroups, numRowGroups, nsnull); + else { // it's an unknown frame type, give it a generic reflow and ignore the results + nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, + nsSize(0,0), eReflowReason_Resize); + nsHTMLReflowMetrics unusedDesiredSize(nsnull); + nsReflowStatus status; + ReflowChild(kidFrame, aPresContext, unusedDesiredSize, kidReflowState, + 0, 0, 0, status); + kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } } - else {// it's an unknown frame type, give it a generic reflow and ignore the results - nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, - nsSize(0,0), eReflowReason_Resize); - nsHTMLReflowMetrics unusedDesiredSize(nsnull); - nsReflowStatus status; - ReflowChild(kidFrame, aPresContext, unusedDesiredSize, kidReflowState, - 0, 0, 0, status); - kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + else if (childX < numRowGroups) { // it is a row group but isn't being reflowed + nsRect kidRect; + kidFrame->GetRect(kidRect); + if (haveReflowedRowGroup) { + if (kidRect.y != aReflowState.y) { + Invalidate(aPresContext, kidRect); // invalidate the old position + kidRect.y = aReflowState.y; + kidFrame->SetRect(aPresContext, kidRect); // move to the new position + Invalidate(aPresContext, kidRect); // invalidate the new position + } + } + aReflowState.y += cellSpacingY + kidRect.height; } } + // if required, give the colgroups their initial reflows + if (aDoColGroups) { + nsHTMLReflowMetrics kidMet(nsnull); + for (nsIFrame* kidFrame = mColGroups.FirstChild(); kidFrame; kidFrame->GetNextSibling(&kidFrame)) { + nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, + aReflowState.availSize, aReflowState.reason); + ReflowChild(kidFrame, aPresContext, kidMet, kidReflowState, 0, 0, 0, aStatus); + FinishReflowChild(kidFrame, aPresContext, kidMet, 0, 0, 0); + } + SetHaveReflowedColGroups(PR_TRUE); + } + + if (aReflowedAtLeastOne) { + *aReflowedAtLeastOne = haveReflowedRowGroup; + } return rv; } @@ -3210,20 +2984,19 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext * @return true if we successfully pulled-up all the children and false * otherwise, e.g. child didn't fit */ -NS_METHOD nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus) { - nsTableFrame* nextInFlow = (nsTableFrame*)mNextInFlow; - nsSize kidMaxElementSize(0,0); - nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; - nsIFrame* prevKidFrame = mFrames.LastChild(); - nsresult rv = NS_OK; + nsTableFrame* nextInFlow = (nsTableFrame*)mNextInFlow; + nsIFrame* prevKidFrame = mFrames.LastChild(); + nsresult rv = NS_OK; - while (nsnull != nextInFlow) { - nsHTMLReflowMetrics kidSize(pKidMaxElementSize); - kidSize.width=kidSize.height=kidSize.ascent=kidSize.descent=0; + while (nextInFlow) { + nsHTMLReflowMetrics kidSize(nsnull); + kidSize.width = kidSize.height = kidSize.ascent = kidSize.descent=0; // XXX change to use nsFrameList::PullFrame @@ -3277,10 +3050,8 @@ NS_METHOD nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, const nsStyleDisplay *childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) - { - PlaceChild(aPresContext, aReflowState, kidFrame, kidSize, 0, - aReflowState.y, aDesiredSize.maxElementSize, *pKidMaxElementSize); + if (IsRowGroup(childDisplay->mDisplay)) { + PlaceChild(aPresContext, aReflowState, kidFrame, kidSize); } else { kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } @@ -3291,7 +3062,7 @@ NS_METHOD nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, // Link the frame into our list of children kidFrame->SetParent(this); - if (nsnull == prevKidFrame) { + if (!prevKidFrame) { mFrames.SetFrames(kidFrame); } else { prevKidFrame->SetNextSibling(kidFrame); @@ -3310,13 +3081,11 @@ NS_METHOD nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, // continuing frame. The creation appends it to the flow and // prepares it for reflow. nsIFrame* continuingFrame; - nsIPresShell* presShell; - nsIStyleSet* styleSet; - aPresContext->GetShell(&presShell); - presShell->GetStyleSet(&styleSet); - NS_RELEASE(presShell); + nsCOMPtr presShell; + nsCOMPtr styleSet; + aPresContext->GetShell(getter_AddRefs(presShell)); + presShell->GetStyleSet(getter_AddRefs(styleSet)); styleSet->CreateContinuingFrame(aPresContext, kidFrame, this, &continuingFrame); - NS_RELEASE(styleSet); // Add the continuing frame to our sibling list and then push // it to the next-in-flow. This ensures the next-in-flow's @@ -3341,93 +3110,60 @@ NS_METHOD nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, to assign widths to each column. */ // use the cell map to determine which cell is in which column. -void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - const nsSize& aMaxSize, - nsSize* aMaxElementSize) +void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState) { - NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); - nsTableCellMap* cellMap = GetCellMap(); - if (!cellMap) { - NS_ASSERTION(PR_FALSE, "never ever call me until the cell map is built!"); - return; - } + NS_ASSERTION(!mPrevInFlow, "never ever call me on a continuing frame!"); - PRInt32 numCols = cellMap->GetColCount(); - if (numCols>mColumnWidthsLength) - { - PRInt32 priorColumnWidthsLength=mColumnWidthsLength; - if (0 == priorColumnWidthsLength) { - mColumnWidthsLength = numCols; - } else { - while (numCols>mColumnWidthsLength) - mColumnWidthsLength += kColumnWidthIncrement; - } - PRInt32 * newColumnWidthsArray = new PRInt32[mColumnWidthsLength]; - if (!newColumnWidthsArray) return; - nsCRT::memset (newColumnWidthsArray, 0, mColumnWidthsLength*sizeof(PRInt32)); - if (mColumnWidths) { - nsCRT::memcpy (newColumnWidthsArray, mColumnWidths, priorColumnWidthsLength*sizeof(PRInt32)); - delete [] mColumnWidths; - } - mColumnWidths = newColumnWidthsArray; + // fixed-layout tables need to reinitialize the layout strategy. When there are scroll bars + // reflow gets called twice and the 2nd time has the correct space available. + // XXX this is very bad and needs to be changed + if (!IsAutoLayout()) { + mTableLayoutStrategy->Initialize(aPresContext, aReflowState); } // need to figure out the overall table width constraint // default case, get 100% of available space - PRInt32 maxWidth = CalcBorderBoxWidth(aReflowState); - - // based on the compatibility mode, create a table layout strategy - nscoord boxWidth = CalcBorderBoxWidth(aReflowState); - if (nsnull == mTableLayoutStrategy) { - nsCompatibility mode; - aPresContext->GetCompatibilityMode(&mode); - if (!IsAutoLayout()) - mTableLayoutStrategy = new FixedTableLayoutStrategy(this); - else - mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); - if (!mTableLayoutStrategy) return; - mTableLayoutStrategy->Initialize(aPresContext, aMaxElementSize, boxWidth, aReflowState); - mBits.mColumnWidthsValid=PR_TRUE; - } - // fixed-layout tables need to reinitialize the layout strategy. When there are scroll bars - // reflow gets called twice and the 2nd time has the correct space available. - else if (!IsAutoLayout()) { - mTableLayoutStrategy->Initialize(aPresContext, aMaxElementSize, boxWidth, aReflowState); - } - - mTableLayoutStrategy->BalanceColumnWidths(aPresContext, mStyleContext, aReflowState, maxWidth); + mTableLayoutStrategy->BalanceColumnWidths(aPresContext, aReflowState); //Dump(PR_TRUE, PR_TRUE); - mBits.mColumnWidthsSet=PR_TRUE; + SetNeedStrategyBalance(PR_FALSE); // we have just balanced + // cache the min, desired, and preferred widths + nscoord minWidth, prefWidth; + CalcMinAndPreferredWidths(aReflowState, minWidth, prefWidth); + SetMinWidth(minWidth); + nscoord desWidth = CalcDesiredWidth(aReflowState); + SetDesiredWidth(desWidth); + SetPreferredWidth(prefWidth); - // if collapsing borders, compute the top and bottom edges now that we have column widths - if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { - mBorderCollapser->ComputeHorizontalBorders(aPresContext, 0, cellMap->GetRowCount()-1); +#ifdef DEBUG_TABLE_REFLOW + printf("Balanced min=%d des=%d pref=%d cols=", minWidth, desWidth, prefWidth); + for (PRInt32 colX = 0; colX < GetColCount(); colX++) { + printf("%d ", GetColumnWidth(colX)); } + printf("\n"); +#endif + } -/** - sum the width of each column - add in table insets - set rect - */ -void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState) +// This width is based on the column widths array of the table. +// sum the width of each column and add in table insets +nscoord +nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState) { - NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); + NS_ASSERTION(!mPrevInFlow, "never ever call me on a continuing frame!"); nsTableCellMap* cellMap = GetCellMap(); if (!cellMap) { NS_ASSERTION(PR_FALSE, "never ever call me until the cell map is built!"); - return; + return 0; } nscoord cellSpacing = GetCellSpacingX(); - PRInt32 tableWidth = 0; + PRInt32 tableWidth = 0; PRInt32 numCols = GetColCount(); for (PRInt32 colIndex = 0; colIndex < numCols; colIndex++) { - nscoord totalColWidth = mColumnWidths[colIndex]; + nscoord totalColWidth = GetColumnWidth(colIndex); if (GetNumCellsOriginatingInCol(colIndex) > 0) { // skip degenerate cols totalColWidth += cellSpacing; // add cell spacing to left of col } @@ -3436,25 +3172,11 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext, if (numCols > 0) { tableWidth += cellSpacing; // add last cellspacing + // Compute the insets (sum of border and padding) + tableWidth += GetHorBorderPaddingWidth(aReflowState, this); } - else if (0 == tableWidth) { - nsRect tableRect = mRect; - tableRect.width = 0; - SetRect(aPresContext, tableRect); - return; - } - // Compute the insets (sum of border and padding) - nsMargin borderPadding; - GetTableBorder (borderPadding); // this gets the max border value at every edge - borderPadding += aReflowState.mComputedPadding; - - nscoord rightInset = borderPadding.right; - nscoord leftInset = borderPadding.left; - tableWidth += (leftInset + rightInset); - nsRect tableSize = mRect; - tableSize.width = tableWidth; - SetRect(aPresContext, tableSize); + return tableWidth; } /** @@ -3465,9 +3187,10 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext, we assume we are passed in the default table height==the sum of the heights of the table's rowgroups in aDesiredSize.height. */ -void nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsIFrame* aRowGroupFrame) +void +nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aRowGroupFrame) { // now that all of the rows have been resized, resize the cells nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame; @@ -3485,13 +3208,14 @@ void nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext, } } -void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsIFrame* aRowGroupFrame, - nscoord aSumOfRowHeights, - nscoord aExcess, - nscoord& aExcessForRowGroup, - nscoord& aRowGroupYPos) +void +nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aRowGroupFrame, + nscoord aSumOfRowHeights, + nscoord aExcess, + nscoord& aExcessForRowGroup, + nscoord& aRowGroupYPos) { // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] // and the rowgroup itself needs to be expanded by SUM(row height deltas) @@ -3502,230 +3226,269 @@ void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, while (rowFrame) { const nsStyleDisplay *rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { - DistributeSpaceToRows(aPresContext, aReflowState, rowFrame, aSumOfRowHeights, - aExcess, aExcessForRowGroup, y); - } - else if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { // the row needs to be expanded by the proportion this row contributed to the original height nsRect rowRect; rowFrame->GetRect(rowRect); float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights; nscoord excessForRow = NSToCoordRound((float)aExcess * percent); - if (rowGroupFrame->RowsDesireExcessSpace()) { - nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height); - rowFrame->SetRect(aPresContext, newRowRect); - if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { - PRInt32 rowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); - mBorderCollapser->SetBorderEdgeLength(NS_SIDE_LEFT, rowIndex, newRowRect.height); - mBorderCollapser->SetBorderEdgeLength(NS_SIDE_RIGHT, rowIndex, newRowRect.height); - } - // better if this were part of an overloaded row::SetRect - y += excessForRow + rowRect.height; - } - y += cellSpacingY; + nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height); + rowFrame->SetRect(aPresContext, newRowRect); + // better if this were part of an overloaded row::SetRect + y += excessForRow + rowRect.height + cellSpacingY; aExcessForRowGroup += excessForRow; } - else { // XXX why - nsRect rowRect; - rowFrame->GetRect(rowRect); - y += rowRect.height; - } rowGroupFrame->GetNextFrame(rowFrame, &rowFrame); } nsRect rowGroupRect; aRowGroupFrame->GetRect(rowGroupRect); - if (rowGroupFrame->RowGroupDesiresExcessSpace()) { - nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width, - aExcessForRowGroup + rowGroupRect.height); - aRowGroupFrame->SetRect(aPresContext, newRowGroupRect); - aRowGroupYPos += aExcessForRowGroup + rowGroupRect.height; - } - else { - aRowGroupYPos += rowGroupRect.height; - } + nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width, + aExcessForRowGroup + rowGroupRect.height); + aRowGroupFrame->SetRect(aPresContext, newRowGroupRect); + aRowGroupYPos += aExcessForRowGroup + rowGroupRect.height; DistributeSpaceToCells(aPresContext, aReflowState, aRowGroupFrame); } -nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nscoord aDefaultHeight) +nscoord +nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState) { nsTableCellMap* cellMap = GetCellMap(); if (!cellMap) { NS_ASSERTION(PR_FALSE, "never ever call me until the cell map is built!"); return 0; } - nscoord result = aDefaultHeight; - nscoord cellSpacingY = GetCellSpacingY(); + nscoord cellSpacingY = GetCellSpacingY(); + nsMargin borderPadding = GetBorderPadding(aReflowState); + // get the natural height based on the last child's (row group or scroll frame) rect + nsVoidArray rowGroups; + PRUint32 numRowGroups; + OrderRowGroups(rowGroups, numRowGroups, nsnull); + if (numRowGroups <= 0) return 0; + + nsIFrame* lastChild = (nsIFrame*)rowGroups.ElementAt(numRowGroups - 1); + if (!lastChild) return 0; + + nsRect lastRect; + lastChild->GetRect(lastRect); + + nscoord naturalHeight = lastRect.YMost() + cellSpacingY + borderPadding.bottom; + nscoord desiredHeight = naturalHeight; + + // see if a specified table height requires diving additional space to rows nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); - if ((tableSpecifiedHeight > 0) && (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { - if (tableSpecifiedHeight > aDefaultHeight) { - result = tableSpecifiedHeight; + if ((tableSpecifiedHeight > 0) && + (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) && + (tableSpecifiedHeight > naturalHeight)) { + desiredHeight = tableSpecifiedHeight; - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) { - // proportionately distribute the excess height to each row. Note that we - // don't need to do this if it's an unconstrained reflow - nscoord excess = tableSpecifiedHeight - aDefaultHeight; - nscoord sumOfRowHeights = 0; - nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY; + if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) { + // proportionately distribute the excess height to each row. Note that we + // don't need to do this if it's an unconstrained reflow + nscoord excess = tableSpecifiedHeight - naturalHeight; + nscoord sumOfRowHeights = 0; + nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY; - nsVoidArray rowGroups; - PRUint32 numRowGroups; - OrderRowGroups(rowGroups, numRowGroups, nsnull); + nsVoidArray rowGroups; + PRUint32 numRowGroups; + OrderRowGroups(rowGroups, numRowGroups, nsnull); - PRUint32 rgX; - for (rgX = 0; rgX < numRowGroups; rgX++) { - nsTableRowGroupFrame* rgFrame = - GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX)); - if (rgFrame) { - if (rgFrame->RowGroupReceivesExcessSpace()) { - rgFrame->GetHeightOfRows(aPresContext, sumOfRowHeights); - } + PRUint32 rgX; + for (rgX = 0; rgX < numRowGroups; rgX++) { + nsTableRowGroupFrame* rgFrame = + GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX)); + if (rgFrame) { + sumOfRowHeights += rgFrame->GetHeightOfRows(aPresContext); + } + } + + for (rgX = 0; rgX < numRowGroups; rgX++) { + nsTableRowGroupFrame* rgFrame = + GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX)); + if (rgFrame) { + nscoord excessForGroup = 0; + const nsStyleTable* tableStyle; + GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); + DistributeSpaceToRows(aPresContext, aReflowState, rgFrame, sumOfRowHeights, + excess, excessForGroup, rowGroupYPos); + + // Make sure child views are properly positioned + // XXX what happens if childFrame is a scroll frame and this gets skipped? + nsTableFrame::RePositionViews(aPresContext, rgFrame); + } + rowGroupYPos += cellSpacingY; + } + } + } + return desiredHeight; +} + + +PRBool +nsTableFrame::CellChangedWidth(const nsTableCellFrame& aCellFrame, + nscoord aPrevCellMin, + nscoord aPrevCellMax, + PRBool aCellWasDestroyed) +{ + if (NeedStrategyInit() || !IsAutoLayout()) { + // if the strategy needs to be initialized, all of the col info will be updated later + // fixed layout tables do not cause any rebalancing + return PR_TRUE; + } + + nscoord colSpan = GetEffectiveColSpan(aCellFrame); + if (colSpan > 1) { + // colspans are too complicated to optimize, so just bail out + SetNeedStrategyInit(PR_TRUE); + return PR_TRUE; + } + + PRInt32 colIndex; + aCellFrame.GetColIndex(colIndex); + nsTableColFrame* colFrame = GetColFrame(colIndex); + if (!colFrame) return PR_TRUE; // should never happen + + nscoord cellMin = (aCellWasDestroyed) ? 0 : aCellFrame.GetPass1MaxElementSize().width; + nscoord cellMax = (aCellWasDestroyed) ? 0 : aCellFrame.GetMaximumWidth(); + nscoord colMin = colFrame->GetWidth(MIN_CON); + nscoord colMax = colFrame->GetWidth(DES_CON); + + PRBool colMinChanged = PR_TRUE; + if (((cellMin > aPrevCellMin) && (cellMin <= colMin)) || + (cellMin == aPrevCellMin) || + // this assumes that the cell was the only contributor to the current min width + ((cellMin < aPrevCellMin) && (aPrevCellMin != colMin))) { + colMinChanged = PR_FALSE; + } + if (colMinChanged) { + // update the columns's min width + colFrame->SetWidth(MIN_CON, cellMin); + if (ColIsSpannedInto(colIndex)) { + // bail out if a colspan is involved + SetNeedStrategyInit(PR_TRUE); + return PR_TRUE; + } + else { + // we should rebalance in case the min width determines the column width + SetNeedStrategyBalance(PR_TRUE); + } + } + + PRBool colMaxChanged = PR_TRUE; + if (((cellMax > aPrevCellMax) && (cellMax <= colMax)) || + (cellMax == aPrevCellMax) || + // this conservatively assumes that the cell was the only contributor to the current max width + ((cellMax < aPrevCellMax) && (aPrevCellMax != colMax))) { + colMaxChanged = PR_FALSE; + } + if (colMaxChanged) { + // update the column's max width + colFrame->SetWidth(DES_CON, cellMax); + // see if the max width will be not be overshadowed by a pct, fix, or proportional width + if ((colFrame->GetWidth(PCT) <= 0) && (colFrame->GetWidth(FIX) <= 0) && + (colFrame->GetWidth(MIN_PRO) <= 0)) { + // see if the cell is new and doesn't have a pct or fix width + if ((0 == aPrevCellMin) && (0 == aPrevCellMax)) { + const nsStylePosition* cellPosition; + aCellFrame.GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + // see if there isn't a pct width on the cell + PRBool havePct = PR_FALSE; + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + if (percent > 0.0f) { + havePct = PR_TRUE; } } - - for (rgX = 0; rgX < numRowGroups; rgX++) { - nsTableRowGroupFrame* rgFrame = - GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX)); - if (rgFrame) { - if (rgFrame->RowGroupReceivesExcessSpace()) { - nscoord excessForGroup = 0; - const nsStyleTable* tableStyle; - GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - DistributeSpaceToRows(aPresContext, aReflowState, rgFrame, sumOfRowHeights, - excess, excessForGroup, rowGroupYPos); - - // Make sure child views are properly positioned - // XXX what happens if childFrame is a scroll frame and this gets skipped? - nsIView* view; - rgFrame->GetView(aPresContext, &view); - if (view) { - nsContainerFrame::PositionFrameView(aPresContext, rgFrame, view); - } else { - nsContainerFrame::PositionChildViews(aPresContext, rgFrame); - } + if (!havePct) { + // see if there isn't a fix width on the cell + PRBool haveFix = PR_FALSE; + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + nscoord coordValue = cellPosition->mWidth.GetCoordValue(); + if (coordValue > 0) { + haveFix = PR_TRUE; + } + } + if (!haveFix) { + if (ColIsSpannedInto(colIndex)) { + // bail out if a colspan is involved + SetNeedStrategyInit(PR_TRUE); + return PR_TRUE; } else { - nsRect rowGroupRect; - rgFrame->GetRect(rowGroupRect); - rowGroupYPos += rowGroupRect.height; + // we should rebalance in case the max width determines the column width + SetNeedStrategyBalance(PR_TRUE); } - rowGroupYPos += cellSpacingY; } } } } } - return result; -} - - -NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame) -{ - aColFrame = (nsTableColFrame *)mColFrames.ElementAt(aColIndex); - return NS_OK; -} - -PRBool nsTableFrame::IsColumnWidthsSet() -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mColumnWidthsSet; -} - -PRBool nsTableFrame::ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const -{ - if (mTableLayoutStrategy) { - return mTableLayoutStrategy->ColumnsCanBeInvalidatedBy(aPrevStyleWidth, aCellFrame); - } return PR_FALSE; } -PRBool nsTableFrame::ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth) const - +void nsTableFrame::SetNeedStrategyBalance(PRBool aValue) { - if (mTableLayoutStrategy) { - return mTableLayoutStrategy->ColumnsCanBeInvalidatedBy(aCellFrame, aConsiderMinWidth); - } - return PR_FALSE; + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); + firstInFlow->mBits.mNeedStrategyBalance = aValue; } -PRBool nsTableFrame::ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const +PRBool nsTableFrame::NeedStrategyBalance() const { - if (mTableLayoutStrategy) { - return mTableLayoutStrategy->ColumnsAreValidFor(aCellFrame, aPrevCellMin, aPrevCellDes); - } - return PR_FALSE; + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); + return (PRBool)firstInFlow->mBits.mNeedStrategyBalance; } -// XXX This could be more incremental -void nsTableFrame::InvalidateColumnWidths() +void nsTableFrame::SetNeedStrategyInit(PRBool aValue) { - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mColumnWidthsValid=PR_FALSE; + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); + firstInFlow->mBits.mNeedStrategyInit = aValue; } -PRBool nsTableFrame::IsColumnWidthsValid() const +PRBool nsTableFrame::NeedStrategyInit() const { - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mColumnWidthsValid; + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); + return (PRBool)firstInFlow->mBits.mNeedStrategyInit; } -PRBool nsTableFrame::IsFirstPassValid() const +void nsTableFrame::SetResizeReflow(PRBool aValue) { - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mFirstPassValid; + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); + firstInFlow->mBits.mDidResizeReflow = aValue; } -void nsTableFrame::InvalidateFirstPassCache() +PRBool nsTableFrame::DidResizeReflow() const { - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mFirstPassValid=PR_FALSE; -} - -PRBool nsTableFrame::IsMaximumWidthValid() const -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mMaximumWidthValid; -} - -void nsTableFrame::InvalidateMaximumWidth() -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mMaximumWidthValid=PR_FALSE; + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); + return (PRBool)firstInFlow->mBits.mDidResizeReflow; } PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex) { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); PRInt32 result = 0; - if (this!=firstInFlow) - result = firstInFlow->GetColumnWidth(aColIndex); - else - { - // Because we lazily allocate the column widths when balancing the - // columns, it may not be allocated yet. For example, if this is - // an incremental reflow. That's okay, just return 0 for the column - // width -#ifdef NS_DEBUG + if (this == firstInFlow) { + nsTableColFrame* colFrame = GetColFrame(aColIndex); + if (colFrame) { + result = colFrame->GetWidth(FINAL); + } + else { + NS_ASSERTION(PR_FALSE, "null col frame"); + result = 0; + } +#if 0 nsTableCellMap* cellMap = GetCellMap(); if (!cellMap) { NS_ASSERTION(PR_FALSE, "no cell map"); @@ -3734,43 +3497,34 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex) PRInt32 numCols = cellMap->GetColCount(); NS_ASSERTION (numCols > aColIndex, "bad arg, col index out of bounds"); #endif - if (nsnull!=mColumnWidths) - result = mColumnWidths[aColIndex]; + } + else { + result = firstInFlow->GetColumnWidth(aColIndex); } return result; } -void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth) +void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth) { - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(firstInFlow, "illegal state -- no first in flow"); - if (this!=firstInFlow) + if (this == firstInFlow) { + nsTableColFrame* colFrame = GetColFrame(aColIndex); + if (colFrame) { + colFrame->SetWidth(FINAL, aWidth); + } + else { + NS_ASSERTION(PR_FALSE, "null col frame"); + } + } + else { firstInFlow->SetColumnWidth(aColIndex, aWidth); - else - { - // Note: in the case of incremental reflow sometimes the table layout - // strategy will call to set a column width before we've allocated the - // column width array - if (!mColumnWidths) { - mColumnWidthsLength = mCellMap->GetColCount(); // mCellMap is valid since first inflow - mColumnWidths = new PRInt32[mColumnWidthsLength]; - if (!mColumnWidths) return; - nsCRT::memset (mColumnWidths, 0, mColumnWidthsLength*sizeof(PRInt32)); - } - - if (nsnull!=mColumnWidths && aColIndexGetStyleData(eStyleStruct_Color); // Look until we find a style context with a NON-transparent background color - while (styleContext) - { - if ((colorData->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)!=0) - { + while (styleContext) { + if ((colorData->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) != 0) { nsIStyleContext* temp = styleContext; styleContext = styleContext->GetParent(); if (temp != mStyleContext) NS_RELEASE(temp); colorData = (const nsStyleColor*)styleContext->GetStyleData(eStyleStruct_Color); } - else - { + else { break; } } @@ -3810,8 +3561,7 @@ void nsTableFrame::MapHTMLBorderStyle(nsStyleBorder& aBorderStyle, nscoord aBord nscolor borderColor = 0xFFC0C0C0; - if (styleContext != nsnull) - { + if (styleContext) { borderColor = colorData->mBackgroundColor; if (styleContext != mStyleContext) NS_RELEASE(styleContext); @@ -3972,72 +3722,6 @@ nsTableFrame::GetPadding(const nsSize& aBasis, return padding; } -//XXX: ok, this looks dumb now. but in a very short time this will get filled in -void nsTableFrame::GetTableBorder(nsMargin &aBorder) -{ - if (NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) { - mBorderCollapser->GetBorder(aBorder); - } - else { - const nsStyleBorder* border = - (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border); - border->GetBorder(aBorder); - } -} - -/* -now I need to actually use gettableborderat, instead of assuming that the table border is homogenous -across rows and columns. in tableFrame, LayoutStrategy, and cellFrame, maybe rowFrame -need something similar for cell (for those with spans?) -*/ - -void nsTableFrame::GetTableBorderAt(PRInt32 aRowIndex, - PRInt32 aColIndex, - nsMargin& aBorder) -{ - if (NS_STYLE_BORDER_COLLAPSE==GetBorderCollapseStyle()) { - if (mBorderCollapser) { - mBorderCollapser->GetBorderAt(aRowIndex, aColIndex, aBorder); - } - } - else { - const nsStyleBorder* border = - (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border); - border->GetBorder(aBorder); - } -} - -void nsTableFrame::SetBorderEdgeLength(PRUint8 aSide, - PRInt32 aIndex, - nscoord aLength) -{ - if (mBorderCollapser) { - mBorderCollapser->SetBorderEdgeLength(aSide, aIndex, aLength); - } -} - -void nsTableFrame::GetTableBorderForRowGroup(nsTableRowGroupFrame* aRowGroupFrame, - nsMargin& aBorder) -{ - aBorder.SizeTo(0,0,0,0); - if (aRowGroupFrame) { - if (NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) { - if (mBorderCollapser) { - PRInt32 rowCount; - aRowGroupFrame->GetRowCount(rowCount); - nsTableCellMap* cellMap = GetCellMap(); - //PRInt32 colCount = cellMap->GetColCount(); - mBorderCollapser->GetMaxBorder(aRowGroupFrame->GetStartRowIndex(), rowCount - 1, - 0, cellMap->GetColCount() - 1, aBorder); - } - } - else - { - GetTableBorder (aBorder); - } - } -} - PRUint8 nsTableFrame::GetBorderCollapseStyle() { /* the following has been commented out to turn off collapsing borders @@ -4108,21 +3792,20 @@ NS_NewTableFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) return NS_OK; } -NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame) +NS_METHOD +nsTableFrame::GetTableFrame(nsIFrame* aSourceFrame, + nsTableFrame*& aTableFrame) { nsresult rv = NS_ERROR_UNEXPECTED; // the value returned aTableFrame = nsnull; // initialize out-param - nsIFrame *parentFrame=nsnull; - if (nsnull!=aSourceFrame) - { + nsIFrame* parentFrame=nsnull; + if (aSourceFrame) { // "result" is the result of intermediate calls, not the result we return from this method nsresult result = aSourceFrame->GetParent((nsIFrame **)&parentFrame); - while ((NS_OK==result) && (nsnull!=parentFrame)) - { + while ((NS_OK==result) && (nsnull!=parentFrame)) { const nsStyleDisplay *display; parentFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE == display->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE == display->mDisplay) { aTableFrame = (nsTableFrame *)parentFrame; rv = NS_OK; // only set if we found the table frame break; @@ -4158,9 +3841,13 @@ nsTableFrame::IsNested(const nsHTMLReflowState& aReflowState, return result; } -PRBool nsTableFrame::IsAutoWidth() +PRBool +nsTableFrame::IsAutoWidth(PRBool* aIsPctWidth) { PRBool isAuto = PR_TRUE; // the default + if (aIsPctWidth) { + *aIsPctWidth = PR_FALSE; + } nsStylePosition* tablePosition = (nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); switch (tablePosition->mWidth.GetUnit()) { @@ -4173,9 +3860,16 @@ PRBool nsTableFrame::IsAutoWidth() // XXX for now, just return true break; case eStyleUnit_Coord: - case eStyleUnit_Percent: isAuto = PR_FALSE; break; + case eStyleUnit_Percent: + if (tablePosition->mWidth.GetPercentValue() > 0.0f) { + isAuto = PR_FALSE; + if (aIsPctWidth) { + *aIsPctWidth = PR_TRUE; + } + } + break; default: break; } @@ -4183,7 +3877,8 @@ PRBool nsTableFrame::IsAutoWidth() return isAuto; } -nscoord nsTableFrame::CalcBorderBoxWidth(const nsHTMLReflowState& aState) +nscoord +nsTableFrame::CalcBorderBoxWidth(const nsHTMLReflowState& aState) { nscoord width = aState.mComputedWidth; @@ -4210,8 +3905,9 @@ nscoord nsTableFrame::CalcBorderBoxWidth(const nsHTMLReflowState& aState) return width; } -nscoord nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext, - const nsHTMLReflowState& aState) +nscoord +nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aState) { nscoord height = aState.mComputedHeight; if (NS_AUTOHEIGHT != height) { @@ -4223,47 +3919,14 @@ nscoord nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext, return height; } -nscoord nsTableFrame::GetMinCaptionWidth() +nscoord +nsTableFrame::GetMinCaptionWidth() { nsIFrame *outerTableFrame=nsnull; GetParent(&outerTableFrame); return (((nsTableOuterFrame *)outerTableFrame)->GetMinCaptionWidth()); } -/** return the minimum width of the table. Return 0 if the min width is unknown. */ -nscoord nsTableFrame::GetMinTableWidth() -{ - nscoord result = 0; - if (nsnull!=mTableLayoutStrategy) - result = mTableLayoutStrategy->GetTableMinWidth(); - return result; -} - -/** return the maximum width of the table. Return 0 if the max width is unknown. */ -nscoord nsTableFrame::GetMaxTableWidth(const nsHTMLReflowState& aState) -{ - nscoord result = 0; - if (mTableLayoutStrategy) { - if (eStyleUnit_Coord == aState.mStylePosition->mWidth.GetUnit()) { - // only fixed width values are returned as the preferred width - result = PR_MAX(aState.mComputedWidth, mTableLayoutStrategy->GetTableMinWidth()); - } - else { - result = mTableLayoutStrategy->GetTableMaxWidth(aState); - } - } - return result; -} - -void nsTableFrame::SetMaxElementSize(nsSize* aMaxElementSize, - const nsMargin& aPadding) -{ - if (nsnull!=mTableLayoutStrategy) { - mTableLayoutStrategy->SetMaxElementSize(aMaxElementSize, aPadding); - } -} - - PRBool nsTableFrame::IsAutoLayout() { @@ -4289,13 +3952,61 @@ nsTableFrame::GetFrameName(nsString& aResult) const #endif -PRBool -nsTableFrame::IsFinalPass(const nsHTMLReflowState& aState) +void +nsTableFrame::CalcMinAndPreferredWidths(const nsHTMLReflowState& aReflowState, + nscoord& aMinWidth, + nscoord& aPrefWidth) { - return (NS_UNCONSTRAINEDSIZE != aState.availableWidth) || - (NS_UNCONSTRAINEDSIZE != aState.availableHeight); + aMinWidth = aPrefWidth = 0; + + nscoord spacingX = GetCellSpacingX(); + PRInt32 numCols = GetColCount(); + + for (PRInt32 colX = 0; colX < numCols; colX++) { + nsTableColFrame* colFrame = GetColFrame(colX); + if (!colFrame) continue; + aMinWidth += PR_MAX(colFrame->GetMinWidth(), colFrame->GetWidth(MIN_ADJ)); + nscoord width = colFrame->GetPctWidth(); + if (width <= 0) { + width = colFrame->GetFixWidth(); + if (width <= 0) { + width = colFrame->GetWidth(MIN_PRO); + if (width <= 0) { + width = colFrame->GetDesWidth(); + } + } + } + aPrefWidth += width; + if (GetNumCellsOriginatingInCol(colX) > 0) { + aMinWidth += spacingX; + aPrefWidth += spacingX; + } + } + // if it is not a degenerate table, add the last spacing on the right and the borderPadding + if (numCols > 0) { + nscoord extra = spacingX + GetHorBorderPaddingWidth(aReflowState, this); + aMinWidth += extra; + aPrefWidth += extra; + } + aPrefWidth = PR_MAX(aMinWidth, aPrefWidth); + + PRBool isPctWidth = PR_FALSE; + if (!IsAutoWidth(&isPctWidth)) { // a specified fix width becomes the min or preferred width + nscoord compWidth = aReflowState.mComputedWidth; + if ((NS_UNCONSTRAINEDSIZE != compWidth) && (0 != compWidth)) { + compWidth += GetHorBorderPaddingWidth(aReflowState, this); + if (!isPctWidth) { + aMinWidth = PR_MAX(aMinWidth, compWidth); + } + aPrefWidth = PR_MAX(aMinWidth, compWidth); + } + } + if (0 == numCols) { // degenerate case + aMinWidth = aPrefWidth = 0; + } } + // Find the closet sibling before aPriorChildFrame (including aPriorChildFrame) that // is of type aChildType nsIFrame* @@ -4321,7 +4032,7 @@ nsTableFrame::GetFrameAtOrBefore(nsIPresContext* aPresContext, nsIFrame* childFrame; nsIFrame* lastMatchingFrame = nsnull; aParentFrame->FirstChild(aPresContext, nsnull, &childFrame); - while (childFrame && childFrame != aPriorChildFrame) { + while (childFrame && (childFrame != aPriorChildFrame)) { childFrame->GetFrameType(&frameType); if (aChildType == frameType) { lastMatchingFrame = childFrame; @@ -4368,10 +4079,11 @@ nsTableFrame::DumpRowGroup(nsIPresContext* aPresContext, nsIFrame* aKidFrame) } } -void nsTableFrame::Dump(nsIPresContext* aPresContext, - PRBool aDumpRows, - PRBool aDumpCols, - PRBool aDumpCellMap) +void +nsTableFrame::Dump(nsIPresContext* aPresContext, + PRBool aDumpRows, + PRBool aDumpCols, + PRBool aDumpCellMap) { printf("***START TABLE DUMP*** \n"); // dump the columns widths array @@ -4379,7 +4091,7 @@ void nsTableFrame::Dump(nsIPresContext* aPresContext, PRInt32 numCols = GetColCount(); PRInt32 colX; for (colX = 0; colX < numCols; colX++) { - printf("%d ", mColumnWidths[colX]); + printf("%d ", GetColumnWidth(colX)); } printf("\n"); @@ -4600,6 +4312,12 @@ PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const return cellMap->GetNumCellsOriginatingInCol(aColIndex); } + + +/******************************************************************************** + ** DEBUG_TABLE_REFLOW and DEBUG_TABLE_REFLOW_TIMING ** + ********************************************************************************/ + #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING static PRInt32 gRflCount = 0; @@ -4658,6 +4376,16 @@ void DebugGetIndent(const nsIFrame* aFrame, (nsLayoutAtoms::tableCellFrame == frameType.get())) { numLevels++; } + if (nsLayoutAtoms::blockFrame == frameType.get()) { + // only count blocks that are children of cells + nsIFrame* grandParent; + parent->GetParent(&grandParent); + nsCOMPtr gFrameType; + grandParent->GetFrameType(getter_AddRefs(gFrameType)); + if (nsLayoutAtoms::tableCellFrame == gFrameType.get()) { + numLevels++; + } + } parent->GetParent(&parent); } PRInt32 indent = INDENT_PER_LEVEL * numLevels; @@ -4683,7 +4411,8 @@ void nsTableFrame::DebugReflow(nsIFrame* aFrame, char height[16]; if (!aMetrics) { // start PrettyUC(aState.availableWidth, width); - printf("r=%d a=%s ", aState.reason, width); + PrettyUC(aState.availableHeight, height); + printf("r=%d a=%s,%s ", aState.reason, width, height); PrettyUC(aState.mComputedWidth, width); PrettyUC(aState.mComputedHeight, height); printf("c=%s,%s cnt=%d \n", width, height, gRflCount); @@ -4749,9 +4478,11 @@ nsReflowTimer* GetFrameTimer(nsIFrame* aFrame, void DebugReflowPrintAuxTimer(char* aMes, nsReflowTimer* aTimer) { - printf("%s %dms", aMes, aTimer->Elapsed()); - if (aTimer->mNumStarts > 1) { - printf(" times=%d", aTimer->mNumStarts); + if (aTimer->mNumStarts > 0) { + printf("%s %dms", aMes, aTimer->Elapsed()); + if (aTimer->mNumStarts > 1) { + printf(" times=%d", aTimer->mNumStarts); + } } } @@ -4775,24 +4506,31 @@ void DebugReflowPrint(nsReflowTimer& aTimer, printf(" times=%d", aTimer.mNumStarts); if (isTable) { printf("\n%s", indentChar); - DebugReflowPrintAuxTimer("nonPctCols", aTimer.mNextSibling); - DebugReflowPrintAuxTimer(" nonPctColspans", aTimer.mNextSibling->mNextSibling); - DebugReflowPrintAuxTimer(" pctCols", aTimer.mNextSibling->mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer("init", aTimer.mNextSibling); + DebugReflowPrintAuxTimer(" balanceCols", aTimer.mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer(" nonPctCols", aTimer.mNextSibling->mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer(" nonPctColspans", aTimer.mNextSibling->mNextSibling->mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer(" pctCols", aTimer.mNextSibling->mNextSibling->mNextSibling->mNextSibling->mNextSibling); } } else { char avWidth[16]; + char avHeight[16]; char compWidth[16]; char compHeight[16]; char desWidth[16]; char desHeight[16]; PrettyUC(aTimer.mAvailWidth, avWidth); + PrettyUC(aTimer.mAvailWidth, avHeight); PrettyUC(aTimer.mComputedWidth, compWidth); PrettyUC(aTimer.mComputedHeight, compHeight); PrettyUC(aTimer.mDesiredWidth, desWidth); PrettyUC(aTimer.mDesiredHeight, desHeight); - printf(" r=%d a=%s c=%s,%s d=%s,%s", aTimer.mReason, avWidth, compWidth, - compHeight, desWidth, desHeight); + printf(" r=%d", aTimer.mReason); + if (aTimer.mReflowType >= 0) { + printf(",%d", aTimer.mReflowType); + } + printf(" a=%s,%s c=%s,%s d=%s,%s", avWidth, avHeight, compWidth, compHeight, desWidth, desHeight); if (aTimer.mMaxElementWidth >= 0) { PrettyUC(aTimer.mMaxElementWidth, avWidth); printf(" me=%s", avWidth); @@ -4807,9 +4545,11 @@ void DebugReflowPrint(nsReflowTimer& aTimer, printf(" cnt=%d", aTimer.mCount); if (isTable) { printf("\n%s", indentChar); - DebugReflowPrintAuxTimer("nonPctCols", aTimer.mNextSibling); - DebugReflowPrintAuxTimer(" nonPctColspans", aTimer.mNextSibling->mNextSibling); - DebugReflowPrintAuxTimer(" pctCols", aTimer.mNextSibling->mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer("init", aTimer.mNextSibling); + DebugReflowPrintAuxTimer(" balanceCols", aTimer.mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer(" nonPctCols", aTimer.mNextSibling->mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer(" nonPctColspans", aTimer.mNextSibling->mNextSibling->mNextSibling->mNextSibling); + DebugReflowPrintAuxTimer(" pctCols", aTimer.mNextSibling->mNextSibling->mNextSibling->mNextSibling->mNextSibling); } } // print the timer's children @@ -4853,12 +4593,20 @@ void nsTableFrame::DebugReflow(nsIFrame* aFrame, timer->mNextSibling = new nsReflowTimer(aFrame); timer->mNextSibling->mNextSibling = new nsReflowTimer(aFrame); timer->mNextSibling->mNextSibling->mNextSibling = new nsReflowTimer(aFrame); + timer->mNextSibling->mNextSibling->mNextSibling->NextSibling = new nsReflowTimer(aFrame); + timer->mNextSibling->mNextSibling->mNextSibling->NextSibling->mNextSibling = new nsReflowTimer(aFrame); } timer->mReason = aState.reason; timer->mAvailWidth = aState.availableWidth; timer->mComputedWidth = aState.mComputedWidth; timer->mComputedHeight = aState.mComputedHeight; - timer->mCount = gRflCount++; + timer->mCount = gRflCount++; + nsIReflowCommand* reflowCommand = aState.reflowCommand; + if (reflowCommand) { + nsIReflowCommand::ReflowType reflowType; + reflowCommand->GetType(reflowType); + timer->mReflowType = reflowType; + } timer->Start(); aState.mDebugHook = timer; if (parentTimer) { @@ -4896,60 +4644,42 @@ void nsTableFrame::DebugReflow(nsIFrame* aFrame, } } -void nsTableFrame::DebugTimeNonPctCols(nsTableFrame& aFrame, - nsHTMLReflowState& aState, - PRBool aStart) +void nsTableFrame::DebugTimeMethod(nsMethod aMethod, + nsTableFrame& aFrame, + nsHTMLReflowState& aState, + PRBool aStart) { - nsReflowTimer* timer = (nsReflowTimer*)aState.mDebugHook; + nsReflowTimer* baseTimer = (nsReflowTimer*)aState.mDebugHook; + nsReflowTimer* timer; + PRInt32 offset = aMethod; + PRInt32 idx; if (aStart) { #ifdef DEBUG_TABLE_REFLOW_TIMING_DETAIL - timer->mNextSibling->Start(); + timer = baseTimer; + for (idx = 0; idx <= offset; idx++) { + timer = timer->mNextSibling; + } + timer->Start(); #endif - aFrame.mTimer->mNextSibling->Start(); + timer = aFrame.mTimer; + for (idx = 0; idx <= offset; idx++) { + timer = timer->mNextSibling; + } + timer->Start(); } else { #ifdef DEBUG_TABLE_REFLOW_TIMING_DETAIL - timer->mNextSibling->Stop(); + timer = baseTimer; + for (idx = 0; idx <= offset; idx++) { + timer = timer->mNextSibling; + } + timer->Stop(); #endif - aFrame.mTimer->mNextSibling->Stop(); - } -} - -void nsTableFrame::DebugTimeNonPctColspans(nsTableFrame& aFrame, - nsHTMLReflowState& aState, - PRBool aStart) -{ - nsReflowTimer* timer = (nsReflowTimer*)aState.mDebugHook; - if (aStart) { -#ifdef DEBUG_TABLE_REFLOW_TIMING_DETAIL - timer->mNextSibling->mNextSibling->Start(); -#endif - aFrame.mTimer->mNextSibling->mNextSibling->Start(); - } - else { -#ifdef DEBUG_TABLE_REFLOW_TIMING_DETAIL - timer->mNextSibling->mNextSibling->Stop(); -#endif - aFrame.mTimer->mNextSibling->mNextSibling->Stop(); - } -} - -void nsTableFrame::DebugTimePctCols(nsTableFrame& aFrame, - nsHTMLReflowState& aState, - PRBool aStart) -{ - nsReflowTimer* timer = (nsReflowTimer*)aState.mDebugHook; - if (aStart) { -#ifdef DEBUG_TABLE_REFLOW_TIMING_DETAIL - timer->mNextSibling->mNextSibling->mNextSibling->Start(); -#endif - aFrame.mTimer->mNextSibling->mNextSibling->mNextSibling->Start(); - } - else { -#ifdef DEBUG_TABLE_REFLOW_TIMING_DETAIL - timer->mNextSibling->mNextSibling->mNextSibling->Stop(); -#endif - aFrame.mTimer->mNextSibling->mNextSibling->mNextSibling->Stop(); + timer = aFrame.mTimer; + for (idx = 0; idx <= offset; idx++) { + timer = timer->mNextSibling; + } + timer->Stop(); } } @@ -5053,9 +4783,6 @@ nsTableFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const } PRUint32 sum = sizeof(*this); - // Add in the amount of space for the column width array - sum += mColumnWidthsLength * sizeof(PRInt32); - // Add in size of cell map PRUint32 cellMapSize; mCellMap->SizeOf(aHandler, &cellMapSize); @@ -5077,3 +4804,5 @@ nsTableFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const #endif + + diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index 1c87466ee33..99212ad65f0 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -42,7 +42,7 @@ class nsTableBorderCollapser; class nsITableLayoutStrategy; class nsHTMLValue; -struct InnerTableReflowState; +struct nsTableReflowState; struct nsStylePosition; #ifdef DEBUG_TABLE_REFLOW_TIMING @@ -56,6 +56,7 @@ public: mFrame = aFrame; mNextSibling = nsnull; aFrame->GetFrameType(&mFrameType); + mReflowType = -1; Reset(); } @@ -125,6 +126,7 @@ public: nscoord mDesiredHeight; nsReflowStatus mStatus; nsReflowTimer* mNextSibling; + PRInt32 mReflowType; private: ~nsReflowTimer() {} @@ -189,8 +191,14 @@ public: NS_IMETHOD IsPercentageBase(PRBool& aBase) const; - static nsresult AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIFrame* aTableFrame); + static nsresult AppendDirtyReflowCommand(nsIPresShell* aPresShell, + nsIFrame* aFrame); + static nsIPresShell* GetPresShellNoAddref(nsIPresContext* aPresContext); + + static void RePositionViews(nsIPresContext* aPresContext, + nsIFrame* aFrame); + + nsPoint GetFirstSectionOrigin(const nsHTMLReflowState& aReflowState) const; /* * Notification that aAttribute has changed for content inside a table (cell, row, etc) */ @@ -216,28 +224,21 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); + nsMargin GetBorderPadding(const nsHTMLReflowState& aReflowState) const; + /** helper method to find the table parent of any table frame object */ // TODO: today, this depends on display types. This should be changed to rely // on stronger criteria, like an inner table frame atom static NS_METHOD GetTableFrame(nsIFrame* aSourceFrame, nsTableFrame*& aTableFrame); - // calculate the width of aFrame including its border and padding given - // given its reflow state. - nscoord CalcBorderBoxWidth(const nsHTMLReflowState& aReflowState); - - // calculate the height of aFrame including its border and padding given - // its reflow state. - nscoord CalcBorderBoxHeight(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState); - // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. static nsIFrame* GetFrameAtOrBefore(nsIPresContext* aPresContext, nsIFrame* aParentFrame, nsIFrame* aPriorChildFrame, nsIAtom* aChildType); - PRBool IsAutoWidth(); + PRBool IsAutoWidth(PRBool* aIsPctWidth = nsnull); /** @return PR_TRUE if aDisplayType represents a rowgroup of any sort * (header, footer, or body) @@ -306,12 +307,6 @@ public: nsIFrame** aProviderFrame, nsContextProviderRelationship& aRelationship); - /** return the column frame corresponding to the given column index - * there are two ways to do this, depending on whether we have cached - * column information yet. - */ - NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame); - static nsMargin GetPadding(const nsHTMLReflowState& aReflowState, const nsTableCellFrame* aCellFrame); @@ -320,9 +315,6 @@ public: nsFrameList& GetColGroups(); - /** return PR_TRUE if the column width information has been set */ - PRBool IsColumnWidthsSet(); - /** * Get the "type" of the frame * @@ -336,21 +328,6 @@ public: NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; #endif - /** get the max border thickness for each edge */ - void GetTableBorder(nsMargin &aBorder); - - void SetBorderEdgeLength(PRUint8 aSide, - PRInt32 aIndex, - nscoord aLength); - - /** get the border values for the row and column */ - void GetTableBorderAt(PRInt32 aRowIndex, - PRInt32 aColIndex, - nsMargin &aBorder); - - /** get the max border thickness for each edge encompassed by the row group */ - void GetTableBorderForRowGroup(nsTableRowGroupFrame * aRowGroupFrame, nsMargin &aBorder); - /** return the width of the column at aColIndex */ virtual PRInt32 GetColumnWidth(PRInt32 aColIndex); @@ -459,10 +436,10 @@ public: PRInt32 aRowIndex, PRBool aConsiderSpans); - virtual void RemoveRows(nsIPresContext& aPresContext, - PRInt32 aFirstRowFrame, - PRInt32 aNumRowsToRemove, - PRBool aConsiderSpans); + virtual void RemoveRows(nsIPresContext& aPresContext, + nsTableRowFrame& aFirstRowFrame, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans); void AppendRowGroups(nsIPresContext& aPresContext, nsIFrame* aFirstRowGroupFrame); @@ -482,8 +459,6 @@ public: PRBool aRemoveFromCache, PRBool aRemoveFromCellMap); - static PRBool IsFinalPass(const nsHTMLReflowState& aReflowState); - nsTableCellFrame* GetCellInfoAt(PRInt32 aRowX, PRInt32 aColX, PRBool* aOriginates = nsnull, @@ -491,6 +466,9 @@ public: PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const; + PRBool HasPctCol() const; + void SetHasPctCol(PRBool aValue); + PRBool HasCellSpanningPctCol() const; void SetHasCellSpanningPctCol(PRBool aValue); @@ -501,7 +479,7 @@ protected: */ nsTableFrame(); - /** destructor, responsible for mColumnLayoutData and mColumnWidths */ + /** destructor, responsible for mColumnLayoutData */ virtual ~nsTableFrame(); /** implement abstract method on nsHTMLContainerFrame */ @@ -526,6 +504,12 @@ protected: // Calculate the starting column index to use for the specified col group frame PRInt32 CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame); + PRBool DescendantReflowedNotTimeout() const; + void SetDescendantReflowedNotTimeout(PRBool aValue); + PRBool RequestedTimeoutReflow() const; + void SetRequestedTimeoutReflow(PRBool aValue); + void InterruptNotification(nsIPresContext* aPresContext, + PRBool aIsRequest); public: /** first pass of ResizeReflow. * lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and @@ -538,31 +522,24 @@ public: * * @see nsIFrameReflow::Reflow */ - NS_IMETHOD ResizeReflowPass1(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus, - nsReflowReason aReason, - PRBool aDoSiblings); - virtual PRBool RowGroupsShouldBeConstrained() { return PR_FALSE; } - /** do I need to do a reflow? */ virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState); - -protected: - /** second pass of ResizeReflow. - * lays out all table content with aMaxSize(computed_table_width, given_table_height) - * Pass 2 is executed every time the table needs to resize. An optimization is included - * so that if the table doesn't need to actually be resized, no work is done (see NeedsReflow). - * - * @see nsIFrameReflow::Reflow - */ - NS_IMETHOD ResizeReflowPass2(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); + // increment or decrement the count of pending reflow commands targeted at + // descendants. Only rebalance the table when this count goes to 0 or the + // reflow is the last one in a batch (limited by the pres shell). + NS_IMETHOD ReflowCommandNotify(nsIPresShell* aShell, + nsIReflowCommand* aRC, + PRBool aCommandAdded); +protected: + + NS_METHOD ReflowChildren(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + PRBool aDoColGroups, + PRBool aDirtyOnly, + nsReflowStatus& aStatus, + PRBool* aReflowedAtLeastOne = nsnull); // begin incremental reflow methods /** Incremental Reflow attempts to do column balancing with the minimum number of reflow @@ -574,7 +551,6 @@ protected: * @see Reflow */ NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); @@ -582,38 +558,33 @@ protected: * @param aNextFrame the next frame in the reflow target chain * @see nsIFrameReflow::Reflow */ - NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame); + NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, + nsTableReflowState& aReflowStatet, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame); /** process an incremental reflow command targeted at this frame. * @see nsIFrameReflow::Reflow */ - NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus); /** process a style chnaged notification. * @see nsIFrameReflow::Reflow * TODO: needs to be optimized for which attribute was actually changed. */ - NS_IMETHOD IR_StyleChanged(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_StyleChanged(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus); - NS_IMETHOD AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, - InnerTableReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize, - nscoord aDeltaY); + NS_IMETHOD AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsIFrame* aKidFrame, + nscoord aDeltaY); - nsresult RecoverState(InnerTableReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize); + nsresult RecoverState(nsTableReflowState& aReflowState, + nsIFrame* aKidFrame); NS_METHOD CollapseRowGroupIfNecessary(nsIPresContext* aPresContext, nsIFrame* aRowGroupFrame, @@ -625,22 +596,35 @@ protected: NS_METHOD AdjustForCollapsingCols(nsIPresContext* aPresContext, nscoord& aWidth); -// end incremental reflow methods + // end incremental reflow methods - /** return the desired width of this table accounting for the current - * reflow state, and for the table attributes and parent - */ - nscoord ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) const; - /** return the desired height of this table accounting for the current - * reflow state, and for the table attributes and parent - */ - nscoord ComputeDesiredHeight(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nscoord aDefaultHeight); + // WIDTH AND HEIGHT CALCULATION - /** The following two functions are helpers for ComputeDesiredHeight - */ +public: + + // calculate the computed width of aFrame including its border and padding given + // given its reflow state. + nscoord CalcBorderBoxWidth(const nsHTMLReflowState& aReflowState); + + // calculate the computed height of aFrame including its border and padding given + // its reflow state. + nscoord CalcBorderBoxHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); + void CalcMinAndPreferredWidths(const nsHTMLReflowState& aReflowState, + nscoord& aMinWidth, + nscoord& aPreferredWidth); +protected: + + // calcs the width of the table according to the computed widths of each column. + virtual PRInt32 CalcDesiredWidth(const nsHTMLReflowState& aReflowState); + + // return the desired height of this table accounting for the current + // reflow state, and for the table attributes and parent + nscoord CalcDesiredHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); + // The following two functions are helpers for CalcDesiredHeight + void DistributeSpaceToCells(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsIFrame* aRowGroupFrame); @@ -652,27 +636,11 @@ protected: nscoord& aExcessForRowGroup, nscoord& aRowGroupYPos); - void PlaceChild(nsIPresContext* aPresContext, - InnerTableReflowState& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize, - nscoord aX, - nscoord aY, - nsSize* aMaxElementSize, - nsSize& aKidMaxElementSize); + void PlaceChild(nsIPresContext* aPresContext, + nsTableReflowState& aReflowState, + nsIFrame* aKidFrame, + nsHTMLReflowMetrics& aDesiredSize); - /** - * Reflow the frames we've already created - * - * @param aPresContext presentation context to use - * @param aReflowState 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 - */ - NS_IMETHOD ReflowMappedChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus); /** * Try and pull-up frames from our next-in-flow * @@ -681,35 +649,21 @@ protected: * @return true if we successfully pulled-up all the children and false * otherwise, e.g. child didn't fit */ - NS_IMETHOD PullUpChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD PullUpChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsTableReflowState& aReflowState, + nsReflowStatus& aStatus); /** assign widths for each column, taking into account the table content, the effective style, - * the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect. + * the layout constraints, and the compatibility mode. * @param aPresContext the presentation context * @param aTableStyle the resolved style for the table * @param aMaxSize the height and width constraints * @param aMaxElementSize the min size of the largest indivisible object */ virtual void BalanceColumnWidths(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - const nsSize& aMaxSize, - nsSize* aMaxElementSize); + const nsHTMLReflowState& aReflowState); - /** sets the width of the table according to the computed widths of each column. */ - virtual void SetTableWidth(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState); - - /** returns PR_TRUE if the cached pass 1 data is still valid */ - virtual PRBool IsFirstPassValid() const; - - /** returns PR_TRUE if the cached column info is still valid */ - virtual PRBool IsColumnWidthsValid() const; - - /** returns PR_TRUE if the cached pass1 maximum width is still valid */ - virtual PRBool IsMaximumWidthValid() const; nsIFrame* GetFirstBodyRowGroupFrame(); PRBool MoveOverflowToChildList(nsIPresContext* aPresContext); @@ -740,47 +694,38 @@ public: // which spans into the next col PRBool ColHasSpanningCells(PRInt32 aColIndex); - // Returns PR_TRUE if the style width change, aPrevStyleWidth, for aCellFrame - // could require the columns to be rebalanced. This method can be used to - // determine if an incremental reflow on aCellFrame is necessary as the result - // of the style width change. If aConsiderMinWidth is PR_TRUE, then potential - // changes to aCellFrame's min width is considered (however, if considered, - // the function will always return PR_TRUE if the layout strategy is Basic). - PRBool ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, - const nsTableCellFrame& aCellFrame) const; - - // Returns PR_TRUE if potential width changes to aCellFrame could require the - // columns to be rebalanced. This method can be used after an incremental reflow - // of aCellFrame to determine if a pass1 reflow on aCellFrame is necessary. If - // aConsiderMinWidth is PR_TRUE, then potential changes to aCellFrame's min width - // is considered (however, if considered, the function will always return PR_TRUE - // if the layout strategy is Basic). - PRBool ColumnsCanBeInvalidatedBy(const nsTableCellFrame& aCellFrame, - PRBool aConsiderMinWidth = PR_FALSE) const; - - // Returns PR_TRUE if changes to aCellFrame's pass1 min and desired (max) sizes - // don't require the columns to be rebalanced. This method can be used after a - // pass1 reflow of aCellFrame to determine if the columns need rebalancing. - // aPrevCellMin and aPrevCellDes are the values aCellFrame had before the last - // pass1 reflow. - PRBool ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, - nscoord aPrevCellMin, - nscoord aPrevCellDes) const; - - virtual void InvalidateFirstPassCache(); - - virtual void InvalidateColumnWidths(); - - virtual void InvalidateMaximumWidth(); - + // Allows rows to notify the table of additions or changes to a cell's width + // The table uses this to update the appropriate column widths and to decide + // whether to reinitialize (and then rebalance) or rebalance the table. If the + // most extreme measure results (e.g. reinitialize) then PR_TRUE is returned + // indicating that further calls are not going to accomplish anyting. + PRBool CellChangedWidth(const nsTableCellFrame& aCellFrame, + nscoord aPrevMinWidth, + nscoord aPrevMaxWidth, + PRBool aCellWasDestroyed = PR_FALSE); + protected: + PRBool HaveReflowedColGroups() const; + void SetHaveReflowedColGroups(PRBool aValue); + + PRBool DidResizeReflow() const; + void SetResizeReflow(PRBool aValue); + /** Support methods for DidSetStyleContext */ void MapBorderMarginPadding(nsIPresContext* aPresContext); void MapHTMLBorderStyle(nsStyleBorder& aBorderStyle, nscoord aBorderWidth); - PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); + PRBool ConvertToPixelValue(nsHTMLValue& aValue, + PRInt32 aDefault, + PRInt32& aResult); public: + PRBool NeedStrategyInit() const; + void SetNeedStrategyInit(PRBool aValue); + + PRBool NeedStrategyBalance() const; + void SetNeedStrategyBalance(PRBool aValue); + /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ @@ -811,17 +756,13 @@ public: protected: + PRBool HadInitialReflow() const; + void SetHadInitialReflow(PRBool aValue); + void SetColumnDimensions(nsIPresContext* aPresContext, nscoord aHeight, const nsMargin& aReflowState); -#ifdef NS_DEBUG - /** for debugging only - * prints out info about the table layout state, printing columns and their cells - */ - void ListColumnLayoutData(FILE* out, PRInt32 aIndent); -#endif - /** return the number of columns as specified by the input. * has 2 side effects:
* calls SetStartColumnIndex on each nsTableColumn
@@ -862,21 +803,7 @@ public: /* ----- Cell Map public methods ----- */ /** return the minimum width of the table caption. Return 0 if there is no caption. */ nscoord GetMinCaptionWidth(); - /** return the minimum content width of the table (excludes borders and padding). - Return 0 if the min width is unknown. */ - nscoord GetMinTableWidth(); - - /** return the maximum content width of the table (excludes borders and padding). - Return 0 if the max width is unknown. */ - nscoord GetMaxTableWidth(const nsHTMLReflowState& aReflowState); - - /** compute the max-element-size for the table - * @param aMaxElementSize [OUT] width field set to the min legal width of the table - */ - void SetMaxElementSize(nsSize* aMaxElementSize, - const nsMargin& aPadding); - - /** returns PR_TRUE if table layout requires a preliminary pass over the content */ + /** returns PR_TRUE if table-layout:auto */ virtual PRBool IsAutoLayout(); // compute the height of the table to be used as the basis for @@ -886,6 +813,12 @@ public: /* ----- Cell Map public methods ----- */ nscoord GetPercentBasisForRows(); + nscoord GetMinWidth() const; + void SetMinWidth(nscoord aWidth); + + nscoord GetDesiredWidth() const; + void SetDesiredWidth(nscoord aWidth); + nscoord GetPreferredWidth() const; void SetPreferredWidth(nscoord aWidth); @@ -920,29 +853,39 @@ protected: void DumpRowGroup(nsIPresContext* aPresContext, nsIFrame* aChildFrame); void DebugPrintCount() const; // Debugging routine -// data members - PRInt32 *mColumnWidths; // widths of each column - PRInt32 mColumnWidthsLength; // the number of column lengths this frame has allocated + // DATA MEMBERS struct TableBits { - unsigned mColumnWidthsSet:1; // PR_TRUE if column widths have been set at least once - unsigned mColumnWidthsValid:1; // PR_TRUE if column width data is still legit, PR_FALSE if it needs to be recalculated - unsigned mFirstPassValid:1; // PR_TRUE if first pass data is still legit, PR_FALSE if it needs to be recalculated - unsigned mIsInvariantWidth:1; // PR_TRUE if table width cannot change - unsigned mCellSpansPctCol:1; - unsigned mMaximumWidthValid:1; - int : 26; // unused + unsigned mHadInitialReflow:1; // has intial reflow happened + unsigned mHaveReflowedColGroups:1; // have the col groups gotten their initial reflow + unsigned mNeedStrategyBalance:1; // does the strategy needs to balance the table + unsigned mNeedStrategyInit:1; // does the strategy needs to be initialized and then balance the table + unsigned mHasPctCol:1; // does any cell or col have a pct width + unsigned mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width) + unsigned mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2) + // true if a descendant was reflowed normally since the last time we reflowed. + // We will likely need a timeout reflow (targeted either at us or below) + unsigned mDescendantReflowedNotTimeout:1; + // true if we requested a timeout reflow targeted at us. This will become false if + // we know that a descendant will be getting a timeout reflow and we cancel the one + // targeted at us, as an optimization. + unsigned mRequestedTimeoutReflow:1; + int : 23; // unused } mBits; nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells nsITableLayoutStrategy* mTableLayoutStrategy;// the layout strategy for this frame nsFrameList mColGroups; // the list of colgroup frames - - nsTableBorderCollapser* mBorderCollapser; // one list of border segments for each side of the table frame - // used only for the collapsing border model nscoord mPercentBasisForRows; - nscoord mPreferredWidth; + nscoord mMinWidth; // XXX could store as PRUint16 with pixels + nscoord mDesiredWidth; // XXX could store as PRUint16 with pixels + nscoord mPreferredWidth; // XXX could store as PRUint16 with pixels + // the number of normal incremental reflow commands targeted below this table + PRInt16 mNumDescendantReflowsPending; + // the number of timeout incremental reflow commands targeted below this table + PRInt16 mNumDescendantTimeoutReflowsPending; + // DEBUG REFLOW #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING public: static void DebugReflow(nsIFrame* aFrame, @@ -953,18 +896,11 @@ public: #ifdef DEBUG_TABLE_REFLOW_TIMING static void DebugReflowDone(nsIFrame* aFrame); - static void DebugTimePctCols(nsTableFrame& aFrame, - nsHTMLReflowState& aReflowState, - PRBool aStart); - - static void DebugTimeNonPctCols(nsTableFrame& aFrame, - nsHTMLReflowState& aReflowState, - PRBool aStart); - - static void DebugTimeNonPctColspans(nsTableFrame& aFrame, - nsHTMLReflowState& aReflowState, - PRBool aStart); - + enum nsMethod {eInit=0, eBalanceCols, eNonPctCols, eNonPctColspans, ePctCols}; + static void DebugTimeMethod(nsMethod aMethod, + nsTableFrame& aFrame, + nsHTMLReflowState& aReflowState, + PRBool aStart); nsReflowTimer* mTimer; #endif #endif @@ -983,6 +919,36 @@ inline nscoord nsTableFrame::GetPercentBasisForRows() return mPercentBasisForRows; } +inline void nsTableFrame::SetHadInitialReflow(PRBool aValue) +{ + mBits.mHadInitialReflow = aValue; +} + +inline PRBool nsTableFrame::HadInitialReflow() const +{ + return (PRBool)mBits.mHadInitialReflow; +} + +inline void nsTableFrame::SetHaveReflowedColGroups(PRBool aValue) +{ + mBits.mHaveReflowedColGroups = aValue; +} + +inline PRBool nsTableFrame::HaveReflowedColGroups() const +{ + return (PRBool)mBits.mHaveReflowedColGroups; +} + +inline PRBool nsTableFrame::HasPctCol() const +{ + return (PRBool)mBits.mHasPctCol; +} + +inline void nsTableFrame::SetHasPctCol(PRBool aValue) +{ + mBits.mHasPctCol = (unsigned)aValue; +} + inline PRBool nsTableFrame::HasCellSpanningPctCol() const { return (PRBool)mBits.mCellSpansPctCol; @@ -993,6 +959,26 @@ inline void nsTableFrame::SetHasCellSpanningPctCol(PRBool aValue) mBits.mCellSpansPctCol = (unsigned)aValue; } +inline PRBool nsTableFrame::DescendantReflowedNotTimeout() const +{ + return (PRBool)mBits.mDescendantReflowedNotTimeout; +} + +inline void nsTableFrame::SetDescendantReflowedNotTimeout(PRBool aValue) +{ + mBits.mDescendantReflowedNotTimeout = (unsigned)aValue; +} + +inline PRBool nsTableFrame::RequestedTimeoutReflow() const +{ + return (PRBool)mBits.mRequestedTimeoutReflow; +} + +inline void nsTableFrame::SetRequestedTimeoutReflow(PRBool aValue) +{ + mBits.mRequestedTimeoutReflow = (unsigned)aValue; +} + inline nsFrameList& nsTableFrame::GetColGroups() { return mColGroups; @@ -1003,9 +989,14 @@ inline nsVoidArray& nsTableFrame::GetColCache() return mColFrames; } -inline nscoord nsTableFrame::GetPreferredWidth() const +inline void nsTableFrame::SetMinWidth(nscoord aWidth) { - return mPreferredWidth; + mMinWidth = aWidth; +} + +inline void nsTableFrame::SetDesiredWidth(nscoord aWidth) +{ + mDesiredWidth = aWidth; } inline void nsTableFrame::SetPreferredWidth(nscoord aWidth) @@ -1013,6 +1004,7 @@ inline void nsTableFrame::SetPreferredWidth(nscoord aWidth) mPreferredWidth = aWidth; } + enum nsTableIteration { eTableLTR = 0, diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp index b1495f3ecfc..06fbe67083f 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp @@ -122,21 +122,6 @@ nsresult nsTableOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePt return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); } } - -// helper, should really be in nsFrame -void nsTableOuterFrame::PositionView(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsIView* view; - aFrame->GetView(aPresContext, &view); - if (view) { - nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aFrame, view, nsnull); - } - else { - nsContainerFrame::PositionChildViews(aPresContext, aFrame); - } -} - NS_IMETHODIMP nsTableOuterFrame::IsPercentageBase(PRBool& aBase) const { @@ -404,15 +389,6 @@ NS_IMETHODIMP nsTableOuterFrame::SetSelected(nsIPresContext* aPresContext, return result; } -PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) -{ - PRBool result=PR_TRUE; - if (nsnull != mInnerTableFrame) { - result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState); - } - return result; -} - // GetParentStyleContextProvider: // The innerTableFame is he parent style context provider // Fortunately, we cache that as a data member, so just return the cached pointer value @@ -457,18 +433,18 @@ nsTableOuterFrame::ZeroAutoMargin(nsHTMLReflowState& aReflowState, void FixAutoMargins(nscoord aAvailWidth, + nscoord aChildWidth, nsHTMLReflowState& aReflowState) { // see if there are auto margins. they may have been set to 0 in mComputedMargin PRBool hasAutoMargin = eStyleUnit_Auto == aReflowState.mStyleMargin->mMargin.GetLeftUnit() || eStyleUnit_Auto == aReflowState.mStyleMargin->mMargin.GetRightUnit(); if (hasAutoMargin) { - nsRect rect; - aReflowState.frame->GetRect(rect); - nscoord compWidth = rect.width - aReflowState.mComputedBorderPadding.left - - aReflowState.mComputedBorderPadding.right; - - aReflowState.CalculateBlockSideMargins(aAvailWidth, compWidth); + nscoord width = aChildWidth; + if (NS_UNCONSTRAINEDSIZE == width) { + width = 0; + } + aReflowState.CalculateBlockSideMargins(aAvailWidth, width); } } @@ -487,7 +463,9 @@ GetMarginPadding(nsIPresContext* aPresContext, nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, nsSize(aOuterRS.availableWidth, aOuterRS.availableHeight), eReflowReason_Resize); - FixAutoMargins(aOuterRS.availableWidth, childRS); + nsRect childRect; + aChildFrame->GetRect(childRect); + FixAutoMargins(aOuterRS.availableWidth, childRect.width, childRS); aMargin = childRS.mComputedMargin; aMarginNoAuto = aMargin; nsTableOuterFrame::ZeroAutoMargin(childRS, aMarginNoAuto); @@ -540,7 +518,7 @@ MoveFrameTo(nsIPresContext* aPresContext, aFrame->GetRect(oldRect); if ((oldRect.x != aX) || (oldRect.y != aY)) { aFrame->MoveTo(aPresContext, aX, aY); - nsTableOuterFrame::PositionView(aPresContext, aFrame); + nsTableFrame::RePositionViews(aPresContext, aFrame); } } @@ -653,17 +631,17 @@ nsTableOuterFrame::GetMaxElementSize(const nsMargin& aInnerMargin, const nsMargin& aInnerPadding, const nsMargin& aCaptionMargin) { - nsSize size; - ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(&size, aInnerPadding); - size.width += aInnerMargin.left + aInnerMargin.right; - + nsSize size(0,0); + size.width += aInnerMargin.left + + ((nsTableFrame *)mInnerTableFrame)->GetMinWidth() + + aInnerMargin.right; if (mCaptionFrame) { nscoord capWidth = mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right; if (capWidth > size.width) { size.width = capWidth; } } - size.height = 0; // max element height is not used for anything is it? + // leave max element height set to 0. It is not used for anything return size; } @@ -679,7 +657,8 @@ nsTableOuterFrame::GetMaxWidth(PRUint8 aCaptionSide, case NS_SIDE_LEFT: case NS_SIDE_RIGHT: default: // no caption - maxWidth = mInnerTableMaximumWidth + aInnerMargin.left + aInnerMargin.right; + maxWidth = ((nsTableFrame *)mInnerTableFrame)->GetPreferredWidth() + + aInnerMargin.left + aInnerMargin.right; if (mCaptionFrame) { maxWidth = PR_MAX(maxWidth, mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right); } @@ -915,7 +894,7 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext, childRect.x, childRect.y, NS_FRAME_NO_MOVE_FRAME, aStatus); if (NS_FAILED(rv)) return rv; - FixAutoMargins(aOuterRS.availableWidth, childRS); + FixAutoMargins(aOuterRS.availableWidth, aMetrics.width, childRS); aMargin = childRS.mComputedMargin; aMarginNoAuto = childRS.mComputedMargin; ZeroAutoMargin(childRS, aMarginNoAuto); @@ -1177,6 +1156,7 @@ nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext break; case nsIReflowCommand::StyleChanged : + case nsIReflowCommand::Timeout : rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus); break; @@ -1209,23 +1189,14 @@ nsTableOuterFrame::IR_InnerTableReflow(nsIPresContext* aPresContext, nsSize innerSize; nsMargin innerMargin, innerMarginNoAuto, innerPadding; - // pass along the reflow command to the inner table - nsHTMLReflowMetrics innerMet(aOuterMet.maxElementSize); + // pass along the reflow command to the inner table, requesting the same info in our flags + nsHTMLReflowMetrics innerMet(aOuterMet.maxElementSize, aOuterMet.mFlags); - // request the maximum of the inner table if requested of the outer - if ((aOuterMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) && - ((nsTableFrame*)mInnerTableFrame)->IsAutoLayout()) { - innerMet.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; - } nsresult rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, nsnull, innerSize, innerMargin, innerMarginNoAuto, innerPadding, eReflowReason_Incremental, aStatus); if (NS_FAILED(rv)) return rv; - if (innerMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - mInnerTableMaximumWidth = innerMet.mMaximumWidth; - } - nsPoint innerOrigin(0,0); nsMargin captionMargin(0,0,0,0); nsMargin captionMarginNoAuto(0,0,0,0); @@ -1354,7 +1325,6 @@ nsTableOuterFrame::IR_CaptionInserted(nsIPresContext* aPresContext, nsSize innerSize = GetFrameSize(*mInnerTableFrame); GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, innerMargin, innerMarginNoAuto, innerPadding); - nsPoint innerOrigin; GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, captionMargin, innerSize, innerMargin, innerOrigin); GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, @@ -1421,7 +1391,18 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, } aStatus = NS_FRAME_COMPLETE; - if (eReflowReason_Incremental == aOuterRS.reason) { + PRBool isPaginated; + aPresContext->IsPaginated(&isPaginated); + PRBool needUpdateMetrics = PR_TRUE; + + if (((eReflowReason_Initial == aOuterRS.reason) || (eReflowReason_Resize == aOuterRS.reason)) && + (aOuterRS.availableWidth == mPriorAvailWidth) && + !isPaginated) { + // don't do much if we are resize reflowed exactly like last time + aDesiredSize.width = mRect.width; + aDesiredSize.height = mRect.height; + } + else if (eReflowReason_Incremental == aOuterRS.reason) { rv = IncrementalReflow(aPresContext, aDesiredSize, aOuterRS, aStatus); } else { @@ -1445,83 +1426,79 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, mMinCaptionWidth = maxElementSize.width; } } + // At this point, we must have an inner table frame, and we might have a caption + NS_ASSERTION(mFrames.NotEmpty() && mInnerTableFrame, "incomplete children"); + nsSize innerSize; + nsMargin innerMargin, innerMarginNoAuto, innerPadding; - nsCOMPtr thePrinterContext = do_QueryInterface(aPresContext); + // First reflow the inner table + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); + rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerMarginNoAuto, + innerPadding, aOuterRS.reason, aStatus); + if (NS_FAILED(rv)) return rv; - if ((!thePrinterContext) && - (eReflowReason_Resize == aOuterRS.reason) && - (aOuterRS.availableWidth == mPriorAvailWidth) ) { - // don't do much if we are resize reflowed exactly like last time - nsRect rect; - GetRect(rect); - aDesiredSize.width = rect.width; - aDesiredSize.height = rect.height; - aStatus = NS_FRAME_COMPLETE; - } - else { - // At this point, we must have an inner table frame, and we might have a caption - NS_ASSERTION(mFrames.NotEmpty() && mInnerTableFrame, "incomplete children"); - nsSize innerSize; - nsMargin innerMargin, innerMarginNoAuto, innerPadding; + nsPoint innerOrigin(0,0); + nsMargin captionMargin(0,0,0,0), captionMarginNoAuto(0,0,0,0), ignorePadding; + nsSize captionSize(0,0); + nsSize containSize = GetContainingBlockSize(aOuterRS); - // First reflow the inner table - nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); - rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, - nsnull, innerSize, innerMargin, innerMarginNoAuto, - innerPadding, aOuterRS.reason, aStatus); + // Now that we know the table width we can reflow the caption, and + // place the caption and the inner table + if (mCaptionFrame) { + // reflow the caption + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, + &innerSize.width, &innerMarginNoAuto); + nsHTMLReflowMetrics captionMet(nsnull); + nsReflowStatus capStatus; // don't let the caption cause incomplete + rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, + &availWidth, captionSize, captionMargin, captionMarginNoAuto, + ignorePadding, aOuterRS.reason, capStatus); if (NS_FAILED(rv)) return rv; - if (NS_UNCONSTRAINEDSIZE == aOuterRS.availableWidth) { - // Remember the inner table's maximum width - mInnerTableMaximumWidth = innerMet.width; - } + nsPoint captionOrigin; - nsPoint innerOrigin(0,0); - nsMargin captionMargin(0,0,0,0), captionMarginNoAuto(0,0,0,0), ignorePadding; - nsSize captionSize(0,0); - nsSize containSize = GetContainingBlockSize(aOuterRS); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); - // Now that we know the table width we can reflow the caption, and - // place the caption and the inner table - if (mCaptionFrame) { - // reflow the caption - nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, - &innerSize.width, &innerMarginNoAuto); - nsHTMLReflowMetrics captionMet(nsnull); - nsReflowStatus capStatus; // don't let the caption cause incomplete - rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, - &availWidth, captionSize, captionMargin, captionMarginNoAuto, - ignorePadding, aOuterRS.reason, capStatus); - if (NS_FAILED(rv)) return rv; - - nsPoint captionOrigin; - - GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, - innerMargin, captionSize, captionMargin, captionOrigin); - FinishReflowChild(mCaptionFrame, aPresContext, captionMet, - captionOrigin.x, captionOrigin.y, 0); - - GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, - captionMargin, innerSize, innerMargin, innerOrigin); - - // XXX If the height is constrained then we need to check whether the inner table still fits... - } - else { - GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, captionMargin, innerSize, innerMargin, innerOrigin); - } - FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, - innerOrigin.x, innerOrigin.y, 0); - - UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, - innerPadding, captionMargin, captionMarginNoAuto); + // XXX If the height is constrained then we need to check whether the inner table still fits... + } + else { + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); } + + FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, + innerPadding, captionMargin, captionMarginNoAuto); + needUpdateMetrics = PR_FALSE; } // Return our desired rect aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; + + // compute max element size and maximum width if it hasn't already been + if (needUpdateMetrics) { + nsMargin innerMargin, innerMarginNoAuto, capMargin(0,0,0,0), + capMarginNoAuto(0,0,0,0), innerPadding, capPadding(0,0,0,0); + GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, + innerMargin, innerMarginNoAuto, innerPadding); + if (mCaptionFrame) { + GetMarginPadding(aPresContext, aOuterRS, mCaptionFrame, + capMargin, capMarginNoAuto, capPadding); + } + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, + innerPadding, capMargin, capMarginNoAuto); + } +#ifdef CHECK_THIS_AND_REMOVE // See if we are supposed to compute our maximum width if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { // XXX this needs to consider the possibility of a caption being wider @@ -1530,6 +1507,8 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.mMaximumWidth = ((nsTableFrame*)mInnerTableFrame)->GetPreferredWidth(); } } +#endif + mPriorAvailWidth = aOuterRS.availableWidth; #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.h b/mozilla/layout/html/table/src/nsTableOuterFrame.h index a86487886c9..d0926c26053 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.h +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.h @@ -167,9 +167,6 @@ public: /** @see nsITableFrame::GetTableSize */ NS_IMETHOD GetTableSize(PRInt32& aRowCount, PRInt32& aColCount); - static void PositionView(nsIPresContext* aPresContext, - nsIFrame* aFrame); - static void ZeroAutoMargin(nsHTMLReflowState& aReflowState, nsMargin& aMargin); @@ -184,13 +181,6 @@ protected: * @see nsHTMLContainerFrame::GetSkipSides */ virtual PRIntn GetSkipSides() const; - /** return PR_TRUE if the table needs to be reflowed. - * the outer table needs to be reflowed if the table content has changed, - * or if the table style attributes or parent max height/width have - * changed. - */ - PRBool NeedsReflow(const nsHTMLReflowState& aReflowState); - /** overridden here to handle special caption-table relationship * @see nsContainerFrame::VerifyTree */ @@ -355,9 +345,6 @@ private: /** used to track caption max element size */ PRInt32 mMinCaptionWidth; - - nsSize mMaxElementSize; - nscoord mInnerTableMaximumWidth; nscoord mPriorAvailWidth; #ifdef DEBUG_TABLE_REFLOW_TIMING diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 4db42215453..cb2453d9375 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -153,35 +153,6 @@ nsTableRowFrame::Init(nsIPresContext* aPresContext, return rv; } -// Helper function. It marks the table frame as dirty and generates -// a reflow command -nsresult -nsTableRowFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aTableFrame) -{ - nsFrameState frameState; - nsIFrame* tableParentFrame; - nsIReflowCommand* reflowCmd; - nsresult rv; - - // Mark the table frame as dirty - aTableFrame->GetFrameState(&frameState); - frameState |= NS_FRAME_IS_DIRTY; - aTableFrame->SetFrameState(frameState); - - // Target the reflow comamnd at its parent frame - aTableFrame->GetParent(&tableParentFrame); - rv = NS_NewHTMLReflowCommand(&reflowCmd, tableParentFrame, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - // Add the reflow command - rv = aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - - return rv; -} NS_IMETHODIMP nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext, @@ -196,26 +167,19 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext, nsTableFrame *tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) { - const nsStyleDisplay *display; - childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - - if (NS_STYLE_DISPLAY_TABLE_CELL == display->mDisplay) { + nsCOMPtr frameType; + childFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableCellFrame == frameType.get()) { // Add the cell to the cell map tableFrame->AppendCell(*aPresContext, (nsTableCellFrame&)*childFrame, GetRowIndex()); + // XXX this could be optimized with some effort + tableFrame->SetNeedStrategyInit(PR_TRUE); } } - tableFrame->InvalidateColumnWidths(); - // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames - nsIReflowCommand* reflowCmd; - - if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty))) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } + tableFrame->AppendDirtyReflowCommand(&aPresShell, this); return NS_OK; } @@ -236,12 +200,13 @@ nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext, nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(aPresContext, this, aPrevFrame, nsLayoutAtoms::tableCellFrame); nsVoidArray cellChildren; for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) { - nsIAtom* frameType; - childFrame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableCellFrame == frameType) { + nsCOMPtr frameType; + childFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableCellFrame == frameType.get()) { cellChildren.AppendElement(childFrame); + // XXX this could be optimized with some effort + tableFrame->SetNeedStrategyInit(PR_TRUE); } - NS_IF_RELEASE(frameType); } // insert the cells into the cell map PRInt32 colIndex = -1; @@ -253,18 +218,10 @@ nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext, // Insert the frames in the frame list mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - // Because the number of columns may have changed invalidate the column widths - tableFrame->InvalidateColumnWidths(); - // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames - nsIReflowCommand* reflowCmd; + tableFrame->AppendDirtyReflowCommand(&aPresShell, this); - if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty))) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } return NS_OK; } @@ -278,33 +235,27 @@ nsTableRowFrame::RemoveFrame(nsIPresContext* aPresContext, nsTableFrame* tableFrame=nsnull; nsTableFrame::GetTableFrame(this, tableFrame); if (tableFrame) { - nsIAtom* frameType; - aOldFrame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableCellFrame == frameType) { + nsCOMPtr frameType; + aOldFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableCellFrame == frameType.get()) { nsTableCellFrame* cellFrame = (nsTableCellFrame*)aOldFrame; PRInt32 colIndex; cellFrame->GetColIndex(colIndex); + // remove the cell from the cell map tableFrame->RemoveCell(*aPresContext, cellFrame, GetRowIndex()); + // XXX this could be optimized with some effort + tableFrame->SetNeedStrategyInit(PR_TRUE); // Remove the frame and destroy it mFrames.DestroyFrame(aPresContext, aOldFrame); - // cells have possibly shifted into different columns. - tableFrame->InvalidateColumnWidths(); - - // Because we haven't added any new frames we don't need to do a pass1 - // reflow. Just generate a reflow command so we reflow the table itself. + // XXX This could probably be optimized with much effort + tableFrame->SetNeedStrategyInit(PR_TRUE); + // Generate a reflow command so we reflow the table itself. // Target the row so that it gets a dirty reflow before a resize reflow // in case another cell gets added to the row during a reflow coallesce. - nsIReflowCommand* reflowCmd; - - if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty))) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } + tableFrame->AppendDirtyReflowCommand(&aPresShell, this); } - NS_IF_RELEASE(frameType); } return NS_OK; @@ -341,7 +292,7 @@ GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame, * Post-reflow hook. This is where the table row does its post-processing */ void -nsTableRowFrame::DidResize(nsIPresContext* aPresContext, +nsTableRowFrame::DidResize(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) { // Resize and re-align the cell frames based on our row height @@ -351,13 +302,14 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, nscoord cellSpacingY = tableFrame->GetCellSpacingY(); nsTableIterator iter(aPresContext, *this, eTableDIR); - nsIFrame* cellFrame = iter.First(); + nsIFrame* childFrame = iter.First(); - while (nsnull != cellFrame) { - const nsStyleDisplay *kidDisplay; - cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { - nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst((nsTableCellFrame&) *cellFrame, *tableFrame); + while (childFrame) { + nsCOMPtr frameType; + childFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableCellFrame == frameType.get()) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*)childFrame; + nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame); // resize the cell's height nsSize cellFrameSize; @@ -380,21 +332,11 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, //XXX nsReflowStatus status; //ReflowChild(cellFrame, aPresContext, desiredSize, kidReflowState, status); - ((nsTableCellFrame *)cellFrame)->VerticallyAlignChild(aPresContext, aReflowState, mMaxCellAscent); - - /* if we're collapsing borders, notify the cell that the border edge length has changed */ - if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle()) { - ((nsTableCellFrame *)(cellFrame))->SetBorderEdgeLength(NS_SIDE_LEFT, - GetRowIndex(), - cellHeight); - ((nsTableCellFrame *)(cellFrame))->SetBorderEdgeLength(NS_SIDE_RIGHT, - GetRowIndex(), - cellHeight); - } + cellFrame->VerticallyAlignChild(aPresContext, aReflowState, mMaxCellAscent); } } - // Get the next cell - cellFrame = iter.Next(); + // Get the next child + childFrame = iter.Next(); } // Let our base class do the usual work @@ -620,10 +562,10 @@ void nsTableRowFrame::PaintChildren(nsIPresContext* aPresContext, * sufficient. We have to ask the row if it has a child that contains the point. */ NS_IMETHODIMP -nsTableRowFrame::GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, +nsTableRowFrame::GetFrameForPoint(nsIPresContext* aPresContext, + const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame) + nsIFrame** aFrame) { // XXX This would not need to exist (except as a one-liner, to make this // frame work like a block frame) if rows with rowspan cells made the @@ -670,13 +612,13 @@ nsTableRowFrame::GetFrameForPoint(nsIPresContext* aPresContext, } /* GetMinRowSpan is needed for deviant cases where every cell in a row has a rowspan > 1. - * It sets mMinRowSpan, which is used in FixMinCellHeight and PlaceChild + * It sets mMinRowSpan, which is used in FixMinCellHeight */ void nsTableRowFrame::GetMinRowSpan(nsTableFrame *aTableFrame) { PRInt32 minRowSpan=-1; - nsIFrame *frame=mFrames.FirstChild(); - while (nsnull!=frame) + nsIFrame* frame = mFrames.FirstChild(); + while (frame) { const nsStyleDisplay *kidDisplay; frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); @@ -695,16 +637,13 @@ void nsTableRowFrame::GetMinRowSpan(nsTableFrame *aTableFrame) void nsTableRowFrame::FixMinCellHeight(nsTableFrame *aTableFrame) { - nsIFrame *frame=mFrames.FirstChild(); - while (nsnull!=frame) - { - const nsStyleDisplay *kidDisplay; - frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) - { + nsIFrame* frame = mFrames.FirstChild(); + while (frame) { + nsCOMPtr frameType; + frame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableCellFrame == frameType.get()) { PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame); - if (PRInt32(mBits.mMinRowSpan) ==rowSpan) - { + if (PRInt32(mBits.mMinRowSpan) == rowSpan) { nsRect rect; frame->GetRect(rect); if (rect.height > mTallestCell) @@ -715,34 +654,6 @@ void nsTableRowFrame::FixMinCellHeight(nsTableFrame *aTableFrame) } } -// 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& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize, - nscoord aX, - nscoord aY, - nsSize* aMaxElementSize, - nsSize* aKidMaxElementSize) -{ - // Complete the reflow - FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, aX, aY, 0); - - // update the running total for the row width - aReflowState.x += aDesiredSize.width; - - // Update the maximum element size - PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*aKidFrame); - if (nsnull != aMaxElementSize) { - aMaxElementSize->width += aKidMaxElementSize->width; - if (1 == rowSpan) { - aMaxElementSize->height = PR_MAX(aMaxElementSize->height, aKidMaxElementSize->height); - } - } -} - // Calculate the cell's actual size given its pass2 desired width and height. // Takes into account the specified height (in the style), and any special logic // needed for backwards compatibility. @@ -760,11 +671,10 @@ nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame, aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position); switch (position->mHeight.GetUnit()) { - case eStyleUnit_Coord: - specifiedHeight = position->mHeight.GetCoordValue(); - break; - case eStyleUnit_Percent: - { + case eStyleUnit_Coord: + specifiedHeight = position->mHeight.GetCoordValue(); + break; + case eStyleUnit_Percent: { nsTableFrame* table = nsnull; nsTableFrame::GetTableFrame(this, table); if (table) { @@ -776,11 +686,11 @@ nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame, } break; } - case eStyleUnit_Inherit: - // XXX for now, do nothing - default: - case eStyleUnit_Auto: - break; + case eStyleUnit_Inherit: + // XXX for now, do nothing + case eStyleUnit_Auto: + default: + break; } // If the specified height is greater than the desired height, then use the @@ -797,198 +707,188 @@ nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame, // Calculates the available width for the table cell based on the known // column widths taking into account column spans and column spacing -nscoord -nsTableRowFrame::CalculateCellAvailableWidth(nsTableFrame* aTableFrame, - nsIFrame* aCellFrame, - PRInt32 aCellColIndex, - PRInt32 aNumColSpans, - nscoord aCellSpacingX) +nscoord +CalcCellAvailWidth(nsTableFrame& aTableFrame, + nsTableCellFrame& aCellFrame, + nscoord aCellSpacingX) { - nscoord availWidth = 0; - for (PRInt32 index = 0; index < aNumColSpans; index++) { - // Add in the width of this column - availWidth += aTableFrame->GetColumnWidth(aCellColIndex + index); + nscoord cellWidth = 0; + PRInt32 colIndex; + aCellFrame.GetColIndex(colIndex); + PRInt32 colspan = aTableFrame.GetEffectiveColSpan(aCellFrame); - // If the cell spans columns, then for all columns except the first column - // add in the column spacing - if ((index != 0) && (aTableFrame->GetNumCellsOriginatingInCol(aCellColIndex + index) > 0)) { - availWidth += aCellSpacingX; + for (PRInt32 spanX = 0; spanX < colspan; spanX++) { + nscoord colWidth = aTableFrame.GetColumnWidth(colIndex + spanX); + if (colWidth > 0) { + cellWidth += colWidth; + } + if ((spanX > 0) && (aTableFrame.GetNumCellsOriginatingInCol(colIndex + spanX) > 0)) { + cellWidth += aCellSpacingX; } } - return availWidth; + return cellWidth; } -/** - * Called for a resize reflow. Typically because the column widths have - * changed. Reflows all the existing table cell frames unless aDirtyOnly - * is PR_TRUE in which case only reflow the dirty frames - */ -NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus, - PRBool aDirtyOnly) +nscoord +GetSpaceBetween(PRInt32 aPrevColIndex, + PRInt32 aColIndex, + PRInt32 aColSpan, + nsTableFrame& aTableFrame, + nscoord aCellSpacingX, + PRBool aIsLeftToRight) +{ + nscoord space = 0; + PRInt32 colX; + if (aIsLeftToRight) { + for (colX = aPrevColIndex + 1; aColIndex > colX; colX++) { + space += aTableFrame.GetColumnWidth(colX); + if (aTableFrame.GetNumCellsOriginatingInCol(colX) > 0) { + space += aCellSpacingX; + } + } + } + else { + PRInt32 lastCol = aColIndex + aColSpan - 1; + for (colX = aPrevColIndex - 1; colX > lastCol; colX--) { + space += aTableFrame.GetColumnWidth(colX); + if (aTableFrame.GetNumCellsOriginatingInCol(colX) > 0) { + space += aCellSpacingX; + } + } + } + return space; +} + + +// Called for a dirty or resize reflow. Reflows all the existing table cell +// frames unless aDirtyOnly is PR_TRUE in which case only reflow the dirty frames + +NS_METHOD +nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus, + PRBool aDirtyOnly) { aStatus = NS_FRAME_COMPLETE; - if (nsnull == mFrames.FirstChild()) { - return NS_OK; - } + if (!mFrames.FirstChild()) return NS_OK; + + nsTableFrame* tableFrame = &aTableFrame; + if (!tableFrame) return NS_ERROR_NULL_POINTER; nsresult rv = NS_OK; - ResetTallestCell(aReflowState.reflowState.mComputedHeight); - nsSize localKidMaxElementSize(0,0); - nsSize* kidMaxElementSize = (aDesiredSize.maxElementSize) ? &localKidMaxElementSize : nsnull; - - nscoord cellSpacingX = aReflowState.tableFrame->GetCellSpacingX(); - PRInt32 cellColSpan=1; // must be defined here so it's set properly for non-cell kids + nscoord cellSpacingX = tableFrame->GetCellSpacingX(); + PRInt32 cellColSpan = 1; // must be defined here so it's set properly for non-cell kids - PRInt32 prevColIndex; // remember the col index of the previous cell to handle rowspans into this row - - nsTableFrame* tableFrame = nsnull; - rv = nsTableFrame::GetTableFrame(this, tableFrame); - nsTableIteration dir = (aReflowState.reflowState.availableWidth == NS_UNCONSTRAINEDSIZE) + nsTableIteration dir = (aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE) ? eTableLTR : eTableDIR; nsTableIterator iter(aPresContext, *this, dir); - if (iter.IsLeftToRight()) { - prevColIndex = -1; - } - else { - if (NS_FAILED(rv) || (nsnull == tableFrame)) { - return rv; - } - prevColIndex = tableFrame->GetColCount(); - } + // remember the col index of the previous cell to handle rowspans into this row + PRInt32 firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : tableFrame->GetColCount(); + PRInt32 prevColIndex = firstPrevColIndex; + nscoord x = 0; // running total of children x offset PRBool isAutoLayout = tableFrame->IsAutoLayout(); + PRBool needToNotifyTable = PR_TRUE; // Reflow each of our existing cell frames nsIFrame* kidFrame = iter.First(); - while (nsnull != kidFrame) { + while (kidFrame) { // Get the frame state bits nsFrameState frameState; kidFrame->GetFrameState(&frameState); // See if we should only reflow the dirty child frames - PRBool doReflowChild = PR_TRUE; - if (aDirtyOnly) { - if ((frameState & NS_FRAME_IS_DIRTY) == 0) { - doReflowChild = PR_FALSE; - } + PRBool doReflowChild = PR_TRUE; + if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) { + doReflowChild = PR_FALSE; } + nsCOMPtr frameType; + kidFrame->GetFrameType(getter_AddRefs(frameType)); + // Reflow the child frame - const nsStyleDisplay *kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (doReflowChild) { - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { + if (nsLayoutAtoms::tableCellFrame == frameType.get()) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*)kidFrame; PRInt32 cellColIndex; - ((nsTableCellFrame *)kidFrame)->GetColIndex(cellColIndex); - cellColSpan = aReflowState.tableFrame->GetEffectiveColSpan((nsTableCellFrame &)*kidFrame); + cellFrame->GetColIndex(cellColIndex); + cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame); - // Compute the x-origin for the child, taking into account straddlers (cells from prior - // rows with rowspans > 1) - // if this cell is not immediately adjacent to the previous cell, factor in missing col info - if (iter.IsLeftToRight()) { - if (prevColIndex != (cellColIndex - 1)) { - for (PRInt32 colIndex = prevColIndex + 1; cellColIndex > colIndex; colIndex++) { - aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex); - if (aReflowState.tableFrame->GetNumCellsOriginatingInCol(colIndex) > 0) { - aReflowState.x += cellSpacingX; - } - } - } + x += cellSpacingX; + // If the adjacent cell is in a prior row (because of a rowspan) add in the space + if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) || + (!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) { + x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, *tableFrame, + cellSpacingX, iter.IsLeftToRight()); } - else { - if (prevColIndex != cellColIndex + cellColSpan) { - PRInt32 lastCol = cellColIndex + cellColSpan - 1; - for (PRInt32 colIndex = prevColIndex - 1; colIndex > lastCol; colIndex--) { - aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex); - if (aReflowState.tableFrame->GetNumCellsOriginatingInCol(colIndex) > 0) { - aReflowState.x += cellSpacingX; - } - } - } - } - - aReflowState.x += cellSpacingX; - - // Calculate the available width for the table cell using the known - // column widths - nscoord availWidth; - if (!mPrevInFlow && isAutoLayout && (frameState & NS_FRAME_FIRST_REFLOW)) { - // This is the initial reflow for the cell and so we do an unconstrained - // reflow. - // Note: don't assume that we have known column widths. If we don't, then - // CalculateCellAvailableWidth() may assert if called now... + // Calculate the available width for the table cell using the known column widths + nscoord availWidth = CalcCellAvailWidth(*tableFrame, *cellFrame, cellSpacingX); + if (0 == availWidth) { availWidth = NS_UNCONSTRAINEDSIZE; - } else { - availWidth = CalculateCellAvailableWidth(aReflowState.tableFrame, - kidFrame, cellColIndex, - cellColSpan, cellSpacingX); } - + // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex; - nsHTMLReflowMetrics desiredSize(kidMaxElementSize); + nsHTMLReflowMetrics desiredSize(nsnull); - // If the available width is the same as last time we reflowed the cell, - // then just use the previous desired size and max element size. - // if we need the max-element-size we don't need to reflow. - // we just grab it from the cell frame which remembers it (see the else clause below). - // Note: we can't do that optimization if our height is constrained or the - // cell frame has a next-in-flow + // If the available width is the same as last time we reflowed the cell,then + // use the previous desired size and max element size (else clause). We can't + // do this if our height is constrained or the cell frame has a next-in-flow nsIFrame* kidNextInFlow; kidFrame->GetNextInFlow(&kidNextInFlow); - if ((aReflowState.reflowState.availableHeight != NS_UNCONSTRAINEDSIZE) || - (availWidth != ((nsTableCellFrame *)kidFrame)->GetPriorAvailWidth()) || - (nsnull != kidNextInFlow)) - { - // Reflow the cell to fit the available height - nsSize kidAvailSize(availWidth, aReflowState.reflowState.availableHeight); - + if ((aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) || + (availWidth != cellFrame->GetPriorAvailWidth()) || + kidNextInFlow) { + // Reflow the cell to fit the available width, height + nsSize kidAvailSize(availWidth, aReflowState.availableHeight); + nsReflowReason reason = eReflowReason_Resize; + PRBool newCellToWatch = PR_FALSE; + nsSize maxElementSize; // If it's a dirty frame, then check whether it's the initial reflow - nsReflowReason reason = - (frameState & NS_FRAME_FIRST_REFLOW) ? eReflowReason_Initial :eReflowReason_Resize; - if (!mPrevInFlow && isAutoLayout && (frameState & NS_FRAME_FIRST_REFLOW)) { - // Use an unconstrained width so we can get the child's maximum width - // XXX What about fixed layout tables? - kidAvailSize.SizeTo(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); - // request to get the max element size if not already so - if (!kidMaxElementSize) { - kidMaxElementSize = &localKidMaxElementSize; - desiredSize.maxElementSize = kidMaxElementSize; + if (frameState & NS_FRAME_FIRST_REFLOW) { + reason = eReflowReason_Initial; + cellFrame->DidSetStyleContext(aPresContext); // XXX check this + if (!mPrevInFlow && isAutoLayout) { + // request the maximum width if availWidth is constrained + // XXX we could just do this always, but blocks have some problems + if (NS_UNCONSTRAINEDSIZE != availWidth) { + desiredSize.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; + } + //kidAvailSize.height = NS_UNCONSTRAINEDSIZE; + // request to get the max element size + desiredSize.maxElementSize = &maxElementSize; + newCellToWatch = PR_TRUE; } } - // Reflow the child - nsTableCellReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, - kidAvailSize, reason); + nscoord oldMaxWidth = cellFrame->GetMaximumWidth(); + nscoord oldMaxElemWidth = cellFrame->GetPass1MaxElementSize().width; + // Reflow the child + nsTableCellReflowState kidReflowState(aPresContext, aReflowState, + kidFrame, kidAvailSize, reason); nsReflowStatus status; rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, 0, 0, status); -#ifdef NS_DEBUG_karnaze - if (desiredSize.width > availWidth) - { - printf("WARNING: cell returned desired width %d given avail width %d\n", - desiredSize.width, availWidth); - } -#endif + x, 0, 0, status); - if (eReflowReason_Initial == reason) { - nscoord oldMaxWidth = ((nsTableCellFrame *)kidFrame)->GetMaximumWidth(); - // Save the pass1 reflow information - ((nsTableCellFrame *)kidFrame)->SetMaximumWidth(desiredSize.width); - // invalidate the table's max width if the cell's max width changes - if (oldMaxWidth != desiredSize.mMaximumWidth) { - aReflowState.tableFrame->InvalidateMaximumWidth(); + if (newCellToWatch) { + nscoord maxWidth = (NS_UNCONSTRAINEDSIZE == availWidth) + ? desiredSize.width : desiredSize.mMaximumWidth; + // save the max element width and max width + cellFrame->SetPass1MaxElementSize(desiredSize.width, *desiredSize.maxElementSize); + if (desiredSize.maxElementSize->width > desiredSize.width) { + NS_ASSERTION(PR_FALSE, "max element width exceeded desired width"); + desiredSize.width = desiredSize.maxElementSize->width; } - if (kidMaxElementSize) { - ((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(desiredSize.width, *kidMaxElementSize); - } - // XXX if we did an unconstrained reflow, do we need to do another one - // there needs to be more test cases to show this + cellFrame->SetMaximumWidth(maxWidth); + } + + // allow the table to determine if/how the table needs to be rebalanced + if (newCellToWatch && needToNotifyTable) { + needToNotifyTable = !tableFrame->CellChangedWidth(*cellFrame, oldMaxWidth, oldMaxElemWidth); } // If any of the cells are not complete, then we're not complete @@ -996,24 +896,15 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, aStatus = NS_FRAME_NOT_COMPLETE; } } - else - { - nsSize priorSize = ((nsTableCellFrame *)kidFrame)->GetDesiredSize(); + else { + nsSize priorSize = cellFrame->GetDesiredSize(); desiredSize.width = priorSize.width; desiredSize.height = priorSize.height; - if (kidMaxElementSize) - *kidMaxElementSize = ((nsTableCellFrame *)kidFrame)->GetPass1MaxElementSize(); // Because we may have moved the frame we need to make sure any views are // positioned properly. We have to do this, because any one of our parent // frames could have moved and we have no way of knowing... - nsIView* view; - kidFrame->GetView(aPresContext, &view); - if (view) { - nsContainerFrame::PositionFrameView(aPresContext, kidFrame, view); - } else { - nsContainerFrame::PositionChildViews(aPresContext, kidFrame); - } + nsTableFrame::RePositionViews(aPresContext, kidFrame); } // Calculate the cell's actual size given its pass2 size. This function @@ -1023,19 +914,16 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, desiredSize.height, availWidth); // height may have changed, adjust descent to absorb any excess difference - nscoord ascent = ((nsTableCellFrame *)kidFrame)->GetDesiredAscent(); + nscoord ascent = cellFrame->GetDesiredAscent(); nscoord descent = desiredSize.height - ascent; - SetTallestCell(desiredSize.height, ascent, descent, aReflowState.tableFrame, (nsTableCellFrame*)kidFrame); + SetTallestCell(desiredSize.height, ascent, descent, tableFrame, cellFrame); // Place the child - PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - aReflowState.x, 0, - aDesiredSize.maxElementSize, kidMaxElementSize); - + FinishReflowChild(kidFrame, aPresContext, desiredSize, x, 0, 0); + x += desiredSize.width; } - else - {// it's an unknown frame type, give it a generic reflow and ignore the results - nsTableCellReflowState kidReflowState(aPresContext, aReflowState.reflowState, + else {// it's an unknown frame type, give it a generic reflow and ignore the results + nsTableCellReflowState kidReflowState(aPresContext, aReflowState, kidFrame, nsSize(0,0), eReflowReason_Resize); nsHTMLReflowMetrics desiredSize(nsnull); nsReflowStatus status; @@ -1043,342 +931,161 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } } - else if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { + else if (nsLayoutAtoms::tableCellFrame == frameType.get()) { // we need to account for the cell's width even if it isn't reflowed nsRect rect; kidFrame->GetRect(rect); - aReflowState.x += rect.width; + x += rect.width; } kidFrame = iter.Next(); // Get the next child // if this was the last child, and it had a colspan>1, add in the cellSpacing for the colspan // if the last kid wasn't a colspan, then we still have the colspan of the last real cell - if ((nsnull==kidFrame) && (cellColSpan>1)) - aReflowState.x += cellSpacingX; - } - - // Return our desired size. Note that our desired width is just whatever width - // we were given by the row group frame - aDesiredSize.width = aReflowState.x; - aDesiredSize.height = GetTallestCell(); -#ifdef DEBUG_karnaze - nscoord overAllocated = aDesiredSize.width - aReflowState.reflowState.availableWidth; - if (overAllocated > 0) { - float p2t; - aPresContext->GetScaledPixelsToTwips(&p2t); - if (overAllocated > p2t) { - printf("row over allocated by %d\n twips", overAllocated); - } - } -#endif - - return rv; -} - -/** - * Called for the initial reflow. Creates each table cell frame, and - * reflows it to gets its minimum and maximum sizes - */ -NS_METHOD -nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus, - nsTableCellFrame * aStartFrame, - PRBool aDoSiblings) -{ - nsresult rv = NS_OK; - ResetTallestCell(aReflowState.reflowState.mComputedHeight); - - // Place our children, one at a time, until we are out of children - nsSize kidMaxElementSize(0,0); - nscoord x = 0; - nsTableFrame* table = aReflowState.tableFrame; - PRBool isAutoLayout = table->IsAutoLayout(); - nscoord cellSpacingX = table->GetCellSpacingX(); - - nsIFrame* kidFrame; - if (nsnull==aStartFrame) - kidFrame = mFrames.FirstChild(); - else - kidFrame = aStartFrame; - - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { - const nsStyleDisplay *kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { - // For the initial reflow always allow the child to be as high as it - // wants. The default available width is also unconstrained so we can - // get the child's maximum width - nsSize kidAvailSize; - nsHTMLReflowMetrics kidSize(nsnull); - if (isAutoLayout) { - kidAvailSize.SizeTo(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); - kidSize.maxElementSize=&kidMaxElementSize; - } - else { - PRInt32 colIndex; - ((nsTableCellFrame *)kidFrame)->GetColIndex(colIndex); - kidAvailSize.SizeTo(table->GetColumnWidth(colIndex), NS_UNCONSTRAINEDSIZE); - } - - if (NS_UNCONSTRAINEDSIZE == kidAvailSize.width) { - ((nsTableCellFrame*)kidFrame)->DidSetStyleContext(aPresContext); - } - - nsTableCellReflowState kidReflowState(aPresContext, aReflowState.reflowState, - kidFrame, kidAvailSize, eReflowReason_Initial); - - rv = ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, - x + cellSpacingX, 0, 0, aStatus); - - // the following signals bugs in the content frames. - if (kidMaxElementSize.width > kidSize.width) { -#ifdef DEBUG_karnaze - printf("WARNING - table cell content max element width %d greater than desired width %d\n", - kidMaxElementSize.width, kidSize.width); -#endif - kidSize.width = kidMaxElementSize.width; - } - if (kidMaxElementSize.height > kidSize.height) { -#ifdef DEBUG_karnaze - printf("Warning - table cell content max element height %d greater than desired height %d\n", - kidMaxElementSize.height, kidSize.height); -#endif - kidSize.height = kidMaxElementSize.height; - } - - ((nsTableCellFrame *)kidFrame)->SetMaximumWidth(kidSize.width); - ((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidSize.width, kidMaxElementSize); - NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "unexpected child reflow status"); - - // Place the child + if (!kidFrame && (cellColSpan > 1)) x += cellSpacingX; - // XXX do we need to call CalculateCellActualSize? - PlaceChild(aPresContext, aReflowState, kidFrame, kidSize, x, 0, - aDesiredSize.maxElementSize, &kidMaxElementSize); - SetTallestCell(kidSize.height, kidSize.ascent, kidSize.descent, aReflowState.tableFrame, (nsTableCellFrame*)kidFrame); - x += kidSize.width + cellSpacingX; - } - else - {// it's an unknown frame type, give it a generic reflow and ignore the results - nsTableCellReflowState kidReflowState(aPresContext, aReflowState.reflowState, - kidFrame, nsSize(0,0), eReflowReason_Initial); - nsHTMLReflowMetrics desiredSize(nsnull); - ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, aStatus); - kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - } - if (PR_FALSE==aDoSiblings) - break; } - // Return our desired size - aDesiredSize.width = x; + // just set our width to what was available. The table will calculate the width and not use our value. + aDesiredSize.width = aReflowState.availableWidth; + CalcTallestCell(); aDesiredSize.height = GetTallestCell(); return rv; } -// Recover the reflow state to what it should be if aKidFrame is about -// to be reflowed -// -// The things in the RowReflowState object we need to restore are: -// - max-element size -// - x -NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, - RowReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize) +NS_METHOD nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus) { - // Initialize OUT parameters - if (aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - - // Walk the child frames (except aKidFrame) and find the table cell frames - for (nsIFrame* frame = mFrames.FirstChild(); frame; frame->GetNextSibling(&frame)) { - if (frame != aKidFrame) { - // See if the frame is a table cell frame - const nsStyleDisplay *kidDisplay; - frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { - // Recover the max element size if requested, - // ignoring the height of cells that span rows - if (aMaxElementSize) { - nsSize kidMaxElementSize = ((nsTableCellFrame *)frame)->GetPass1MaxElementSize(); - aMaxElementSize->width += kidMaxElementSize.width; - - PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame); - if (1 == rowSpan) { - aMaxElementSize->height = PR_MAX(aMaxElementSize->height, kidMaxElementSize.height); - } - } - } - } - } - - // Update the running x-offset based on the frame's current x-origin - nsPoint origin; - aKidFrame->GetOrigin(origin); - aReflowState.x = origin.x; - - return NS_OK; -} - - -NS_METHOD nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; + nsresult rv = NS_OK; CalcTallestCell(); // need to recalculate it based on last reflow sizes // determine if this frame is the target or not - nsIFrame *target=nsnull; - rv = aReflowState.reflowState.reflowCommand->GetTarget(target); - if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target)) - { - if (this==target) - rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus); - else - { + nsIFrame* target = nsnull; + rv = aReflowState.reflowCommand->GetTarget(target); + if (target) { + if (this == target) + rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aTableFrame, aStatus); + else { // Get the next frame in the reflow chain nsIFrame* nextFrame; - aReflowState.reflowState.reflowCommand->GetNext(nextFrame); - rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame); + aReflowState.reflowCommand->GetNext(nextFrame); + rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aTableFrame, aStatus, nextFrame); } } return rv; } -NS_METHOD nsTableRowFrame::IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableRowFrame::IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus) { nsresult rv = NS_FRAME_COMPLETE; + nsIReflowCommand::ReflowType type; - aReflowState.reflowState.reflowCommand->GetType(type); - nsIFrame *objectFrame; - aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame); - const nsStyleDisplay *childDisplay=nsnull; - if (nsnull!=objectFrame) - objectFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - switch (type) - { - case nsIReflowCommand::ReflowDirty: - { - // Reflow the dirty child frames. Typically this is newly added frames. - // XXX What we really should do is do a pass-1 reflow of newly added - // frames (only if necessary, i.e., the table isn't fixed layout), then - // see if column widtsh changed and decide whether to do the pass-2 reflow - // of just the dirty rows or have the table rebalance column widths and - // do a pass-2 reflow of all rows - rv = ResizeReflow(aPresContext, aDesiredSize, aReflowState, aStatus, PR_TRUE); - - // If any column widths have to change due to this, rebalance column widths. - // XXX need to calculate this, but for now just do it - aReflowState.tableFrame->InvalidateColumnWidths(); - break; - } - - case nsIReflowCommand::StyleChanged : - rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); - break; - - case nsIReflowCommand::ContentChanged : - NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - - default: - NS_NOTYETIMPLEMENTED("unexpected reflow command type"); - rv = NS_ERROR_NOT_IMPLEMENTED; - break; + aReflowState.reflowCommand->GetType(type); + switch (type) { + case nsIReflowCommand::ReflowDirty: { + // Reflow the dirty child frames. Typically this is newly added frames. + rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, aTableFrame, aStatus, PR_TRUE); + break; + } + case nsIReflowCommand::StyleChanged : + rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aTableFrame, aStatus); + break; + case nsIReflowCommand::ContentChanged : + NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + default: + NS_NOTYETIMPLEMENTED("unexpected reflow command type"); + rv = NS_ERROR_NOT_IMPLEMENTED; + break; } return rv; } -NS_METHOD nsTableRowFrame::IR_StyleChanged(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableRowFrame::IR_StyleChanged(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here // XXX: we can optimize this when we know which style attribute changed - aReflowState.tableFrame->InvalidateFirstPassCache(); + aTableFrame.SetNeedStrategyInit(PR_TRUE); return rv; } -NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame) +NS_METHOD +nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame) { - nsresult rv; + if (!aNextFrame) return NS_ERROR_NULL_POINTER; + nsresult rv = NS_OK; + PRBool isAutoLayout = aTableFrame.IsAutoLayout(); const nsStyleDisplay *childDisplay; aNextFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay) - { - // Recover our reflow state - RecoverState(aPresContext, aReflowState, aNextFrame, aDesiredSize.maxElementSize); + if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*)aNextFrame; + // Get the x coord of the cell + nsPoint cellOrigin; + cellFrame->GetOrigin(cellOrigin); // At this point, we know the column widths. Compute the cell available width PRInt32 cellColIndex; - ((nsTableCellFrame *)aNextFrame)->GetColIndex(cellColIndex); - PRInt32 cellColSpan = aReflowState.tableFrame->GetEffectiveColSpan((nsTableCellFrame &)*aNextFrame); - nscoord cellSpacingX = aReflowState.tableFrame->GetCellSpacingX(); + cellFrame->GetColIndex(cellColIndex); + PRInt32 cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame); + nscoord cellSpacingX = aTableFrame.GetCellSpacingX(); - nscoord cellAvailWidth = CalculateCellAvailableWidth(aReflowState.tableFrame, aNextFrame, - cellColIndex, cellColSpan, cellSpacingX); + nscoord cellAvailWidth = CalcCellAvailWidth(aTableFrame, *cellFrame, cellSpacingX); // Always let the cell be as high as it wants. We ignore the height that's // passed in and always place the entire row. Let the row group decide // whether we fit or wehther the entire row is pushed - nsSize kidAvailSize(cellAvailWidth, NS_UNCONSTRAINEDSIZE); + nsSize cellAvailSize(cellAvailWidth, NS_UNCONSTRAINEDSIZE); // Pass along the reflow command nsSize kidMaxElementSize; // Unless this is a fixed-layout table, then have the cell incrementally - // update its maximum width. XXX should not skip if the cell is in the 1st row - nsHTMLReflowMetrics cellMet(&kidMaxElementSize, aReflowState.tableFrame->IsAutoLayout() ? - NS_REFLOW_CALC_MAX_WIDTH : 0); - nsTableCellReflowState kidRS(aPresContext, aReflowState.reflowState, - aNextFrame, kidAvailSize); + // update its maximum width. + nsHTMLReflowMetrics cellMet(&kidMaxElementSize, isAutoLayout ? + NS_REFLOW_CALC_MAX_WIDTH : 0); + nsTableCellReflowState kidRS(aPresContext, aReflowState, aNextFrame, cellAvailSize); // Remember the current desired size, we'll need it later - nsSize oldCellMinSize = ((nsTableCellFrame*)aNextFrame)->GetPass1MaxElementSize(); - nscoord oldCellMaximumWidth = ((nsTableCellFrame*)aNextFrame)->GetMaximumWidth(); - nsSize oldCellDesSize = ((nsTableCellFrame*)aNextFrame)->GetDesiredSize(); - nscoord oldCellDesAscent = ((nsTableCellFrame*)aNextFrame)->GetDesiredAscent(); + nsSize oldCellMinSize = cellFrame->GetPass1MaxElementSize(); + nscoord oldCellMaximumWidth = cellFrame->GetMaximumWidth(); + nsSize oldCellDesSize = cellFrame->GetDesiredSize(); + nscoord oldCellDesAscent = cellFrame->GetDesiredAscent(); nscoord oldCellDesDescent = oldCellDesSize.height - oldCellDesAscent; // Reflow the cell passing it the incremental reflow command. We can't pass // in a max width of NS_UNCONSTRAINEDSIZE, because the max width must match // the width of the previous reflow... rv = ReflowChild(aNextFrame, aPresContext, cellMet, kidRS, - aReflowState.x, 0, 0, aStatus); + cellOrigin.x, 0, 0, aStatus); nsSize initCellDesSize(cellMet.width, cellMet.height); nscoord initCellDesAscent = cellMet.ascent; nscoord initCellDesDescent = cellMet.descent; - // Update the cell layout data.. If the cell's maximum width changed, - // then inform the table that its maximum width needs to be recomputed - ((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(cellMet.width, kidMaxElementSize); - if (cellMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - ((nsTableCellFrame *)aNextFrame)->SetMaximumWidth(cellMet.mMaximumWidth); - if (oldCellMaximumWidth != cellMet.mMaximumWidth) { - aReflowState.tableFrame->InvalidateMaximumWidth(); - } - } + // cache the max-elem and maximum widths + cellFrame->SetPass1MaxElementSize(cellMet.width, kidMaxElementSize); + cellFrame->SetMaximumWidth(cellMet.mMaximumWidth); // Calculate the cell's actual size given its pass2 size. This function // takes into account the specified height (in the style), and any special @@ -1390,7 +1097,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // if the cell got shorter and it may have been the tallest, recalc the tallest cell PRBool tallestCellGotShorter = PR_FALSE; - PRBool hasVerticalAlignBaseline = ((nsTableCellFrame*)aNextFrame)->HasVerticalAlignBaseline(); + PRBool hasVerticalAlignBaseline = cellFrame->HasVerticalAlignBaseline(); if (!hasVerticalAlignBaseline) { // only the height matters tallestCellGotShorter = @@ -1402,7 +1109,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, TallestCellGotShorter(oldCellDesAscent, cellMet.ascent, mMaxCellAscent); // the descent of cells without rowspan also matters if (!tallestCellGotShorter) { - PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*aNextFrame); + PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan(*cellFrame); if (rowSpan == 1) { tallestCellGotShorter = TallestCellGotShorter(oldCellDesAscent, cellMet.descent, mMaxCellDescent); @@ -1413,14 +1120,17 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, CalcTallestCell(); } else { - SetTallestCell(cellMet.height, cellMet.ascent, cellMet.descent, aReflowState.tableFrame, (nsTableCellFrame*)aNextFrame); + SetTallestCell(cellMet.height, cellMet.ascent, cellMet.descent, &aTableFrame, cellFrame); } // if the cell's desired size didn't changed, our height is unchanged aDesiredSize.mNothingChanged = PR_FALSE; - PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*aNextFrame); + PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan(*cellFrame); if ((initCellDesSize.width == oldCellDesSize.width) && (initCellDesSize.height == oldCellDesSize.height)) { + // XXX replace the line above with these two after testing the performance impact + //(initCellDesSize.height == oldCellDesSize.height) && + //!maxWidthChanged) { if (!hasVerticalAlignBaseline) { // only the cell's height matters aDesiredSize.mNothingChanged = PR_TRUE; } @@ -1437,35 +1147,27 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, cellMet.height = aDesiredSize.height; } else { - nscoord heightOfRows = aDesiredSize.height + GetHeightOfRowsSpannedBelowFirst((nsTableCellFrame&)*aNextFrame, *aReflowState.tableFrame); + nscoord heightOfRows = aDesiredSize.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, aTableFrame); cellMet.height = PR_MAX(cellMet.height, heightOfRows); // XXX need to check what happens when this height differs from height of the cell's previous mRect.height } // Now place the child - PlaceChild(aPresContext, aReflowState, aNextFrame, cellMet, aReflowState.x, - 0, aDesiredSize.maxElementSize, &kidMaxElementSize); + FinishReflowChild(aNextFrame, aPresContext, cellMet, cellOrigin.x, 0, 0); - - // Now that we know the minimum and preferred widths see if the column - // widths need to be rebalanced - if (!aDesiredSize.mNothingChanged && - !aReflowState.tableFrame->ColumnsAreValidFor(*(nsTableCellFrame*)aNextFrame, - oldCellMinSize.width, - oldCellMaximumWidth)) { - // The column widths need to be rebalanced. Tell the table to rebalance - // the column widths - aReflowState.tableFrame->InvalidateColumnWidths(); + // Notify the table if the cell width changed so it can decide whether to rebalance + if (!aDesiredSize.mNothingChanged) { + aTableFrame.CellChangedWidth(*cellFrame, oldCellMinSize.width, oldCellMaximumWidth); } // Return our desired size. Note that our desired width is just whatever width // we were given by the row group frame - aDesiredSize.width = aReflowState.availSize.width; + aDesiredSize.width = aReflowState.availableWidth; if (!aDesiredSize.mNothingChanged) { if (aDesiredSize.height == mRect.height) { // our height didn't change - ((nsTableCellFrame *)aNextFrame)->VerticallyAlignChild(aPresContext, aReflowState.reflowState, mMaxCellAscent); + cellFrame->VerticallyAlignChild(aPresContext, aReflowState, mMaxCellAscent); nsRect dirtyRect; - aNextFrame->GetRect(dirtyRect); + cellFrame->GetRect(dirtyRect); dirtyRect.height = mRect.height; Invalidate(aPresContext, dirtyRect); } @@ -1510,32 +1212,16 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext, #endif nsresult rv = NS_OK; - // Initialize 'out' parameters (aStatus set below, undefined if rv returns an error) - if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = 0; - aDesiredSize.maxElementSize->height = 0; - } - - // Create a reflow state - nsTableFrame *tableFrame=nsnull; + nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv) || nsnull==tableFrame) - return rv; - RowReflowState state(aReflowState, tableFrame); + if (!tableFrame) return NS_ERROR_NULL_POINTER; - // Do the reflow - // XXX If the width is unconstrained, then treat it like we would treat the - // initial reflow instead. This needs to be cleaned up - nsReflowReason reason = aReflowState.reason; - if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { - reason = eReflowReason_Initial; - } - - switch (reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: - rv = InitialReflow(aPresContext, aDesiredSize, state, aStatus, nsnull, PR_TRUE); - if (!tableFrame->IsAutoLayout()) - { // this resize reflow is necessary to place the cells correctly in the case of rowspans and colspans. + rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame, aStatus, PR_TRUE); +#ifdef WHY + if (!tableFrame->IsAutoLayout()) { + // this resize reflow is necessary to place the cells correctly in the case of rowspans and colspans. // It is very efficient. It does not actually need to pass a reflow down to the cells. nsSize availSpace(aReflowState.availableWidth, aReflowState.availableHeight); nsHTMLReflowState resizeReflowState(aPresContext, @@ -1544,8 +1230,9 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext, availSpace, eReflowReason_Resize); RowReflowState rowResizeReflowState(resizeReflowState, tableFrame); - rv = ResizeReflow(aPresContext, aDesiredSize, rowResizeReflowState, aStatus); + rv = ReflowChildren(aPresContext, aDesiredSize, rowResizeReflowState, aStatus); } +#endif //GetMinRowSpan(tableFrame); //FixMinCellHeight(tableFrame); aStatus = NS_FRAME_COMPLETE; @@ -1553,19 +1240,16 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext, case eReflowReason_Resize: case eReflowReason_StyleChange: - rv = ResizeReflow(aPresContext, aDesiredSize, state, aStatus); + rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame, aStatus, PR_FALSE); break; case eReflowReason_Incremental: - rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus); + rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, *tableFrame, aStatus); break; } - // If we computed our max element element size, then cache it so we can return - // it later when asked - if (aDesiredSize.maxElementSize) { - mMaxElementSize = *aDesiredSize.maxElementSize; - } + // just set our width to what was available. The table will calculate the width and not use our value. + aDesiredSize.width = aReflowState.availableWidth; #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus); @@ -1577,7 +1261,9 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext, * so the default "get the child rect, see if it contains the event point" action isn't * sufficient. We have to ask the row if it has a child that contains the point. */ -PRBool nsTableRowFrame::Contains(nsIPresContext* aPresContext, const nsPoint& aPoint) +PRBool +nsTableRowFrame::Contains(nsIPresContext* aPresContext, + const nsPoint& aPoint) { PRBool result = PR_FALSE; // first, check the row rect and see if the point is in their diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index e092b1ee6aa..f5f3f759ec4 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -32,34 +32,6 @@ class nsTableCellFrame; class nsReflowTimer; #endif -/* ----------- RowReflowState ---------- */ - -struct RowReflowState { - // Our reflow state - const nsHTMLReflowState& reflowState; - - // The body's available size (computed from the body's parent) - nsSize availSize; - - // the running x-offset - nscoord x; - - nsTableFrame *tableFrame; - - RowReflowState(const nsHTMLReflowState& aReflowState, - nsTableFrame* aTableFrame) - : reflowState(aReflowState) - { - availSize.width = reflowState.availableWidth; - availSize.height = reflowState.availableHeight; - tableFrame = aTableFrame; - x=0; - } -}; - -/** - * Additional frame-state bits - */ #define NS_TABLE_MAX_ROW_INDEX (1<<19) /** @@ -122,10 +94,10 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); - NS_IMETHOD GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, + NS_IMETHOD GetFrameForPoint(nsIPresContext* aPresContext, + const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame); + nsIFrame** aFrame); /** calls Reflow for all of its child cells. * Cells with rowspan=1 are all set to the same height and stacked horizontally. @@ -140,12 +112,12 @@ public: * @see nsTableFrame::BalanceColumnWidths * @see nsTableFrame::ShrinkWrapChildren */ - NS_IMETHOD Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, + NS_IMETHOD Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); + nsReflowStatus& aStatus); - virtual void DidResize(nsIPresContext* aPresContext, + virtual void DidResize(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState); /** @@ -157,7 +129,8 @@ public: #ifdef DEBUG NS_IMETHOD GetFrameName(nsString& aResult) const; - NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; + NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, + PRUint32* aResult) const; #endif void SetTallestCell(nscoord aHeight, @@ -200,15 +173,14 @@ public: virtual PRBool Contains(nsIPresContext* aPresContext, const nsPoint& aPoint); - void GetMaxElementSize(nsSize& aMaxElementSize) const; - /** used by yje row group frame code */ void ReflowCellFrame(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsTableCellFrame* aCellFrame, nscoord aAvailableHeight, nsReflowStatus& aStatus); - void InsertCellFrame(nsTableCellFrame* aFrame, nsTableCellFrame* aPrevSibling); + void InsertCellFrame(nsTableCellFrame* aFrame, + nsTableCellFrame* aPrevSibling); nsresult CalculateCellActualSize(nsIFrame* aRowFrame, nscoord& aDesiredWidth, @@ -232,30 +204,30 @@ protected: * * @see Reflow */ - NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus); - NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame); + NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame); - NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus); - NS_IMETHOD IR_StyleChanged(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus); - - nsresult AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aTableFrame); + NS_IMETHOD IR_StyleChanged(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus); // row-specific methods @@ -263,52 +235,19 @@ protected: void FixMinCellHeight(nsTableFrame *aTableFrame); - NS_IMETHOD RecoverState(nsIPresContext* aPresContext, - RowReflowState& aState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize); - - void PlaceChild(nsIPresContext* aPresContext, - RowReflowState& aState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize, - nscoord aX, - nscoord aY, - nsSize* aMaxElementSize, - nsSize* aKidMaxElementSize); - - nscoord ComputeCellXOffset(const RowReflowState& aState, - nsIFrame* aKidFrame, - const nsMargin& aKidMargin) const; - nscoord ComputeCellAvailWidth(const RowReflowState& aState, - nsIFrame* aKidFrame) const; - + nscoord ComputeCellXOffset(const nsHTMLReflowState& aState, + nsIFrame* aKidFrame, + const nsMargin& aKidMargin) const; /** - * Called for a resize reflow. Typically because the column widths have - * changed. Reflows all the existing table cell frames + * Called for incremental/dirty and resize reflows. If aDirtyOnly is true then + * only reflow dirty cells. */ - NS_IMETHOD ResizeReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus, - PRBool aDirtyOnly = PR_FALSE); - - /** - * Called for the initial reflow. Creates each table cell frame, and - * reflows the cell frame to gets its minimum and maximum sizes - */ - NS_IMETHOD InitialReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowReflowState& aReflowState, - nsReflowStatus& aStatus, - nsTableCellFrame * aStartFrame, - PRBool aDoSiblings); - - nscoord CalculateCellAvailableWidth(nsTableFrame* aTableFrame, - nsIFrame* aCellFrame, - PRInt32 aCellColIndex, - PRInt32 aNumColSpans, - nscoord aCellSpacingX); + NS_IMETHOD ReflowChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsTableFrame& aTableFrame, + nsReflowStatus& aStatus, + PRBool aDirtyOnly = PR_FALSE); public: struct RowBits { @@ -322,7 +261,6 @@ private: RowBits mBits; }; nscoord mTallestCell; // not my height, but the height of my tallest child - nsSize mMaxElementSize; // cached max element size // max-ascent and max-descent amongst all cells that have 'vertical-align: baseline' nscoord mMaxCellAscent; // does include cells with rowspan > 1 @@ -345,10 +283,4 @@ inline void nsTableRowFrame::SetRowIndex (int aRowIndex) mBits.mRowIndex = aRowIndex; } -inline void nsTableRowFrame::GetMaxElementSize(nsSize& aMaxElementSize) const -{ - aMaxElementSize.width = mMaxElementSize.width; - aMaxElementSize.height = mMaxElementSize.height; -} - #endif diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 6fdff700816..a796c6299f6 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -89,52 +89,38 @@ nsTableRowGroupFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) } } -NS_METHOD nsTableRowGroupFrame::GetRowCount(PRInt32 &aCount, PRBool aDeepCount) -{ - // init out-param - aCount=0; +PRInt32 +nsTableRowGroupFrame::GetRowCount() +{ + PRInt32 count = 0; // init return // loop through children, adding one to aCount for every legit row - nsIFrame *childFrame = GetFirstFrame(); - while (PR_TRUE) - { - if (nsnull==childFrame) + nsIFrame* childFrame = GetFirstFrame(); + while (PR_TRUE) { + if (!childFrame) break; - const nsStyleDisplay *childDisplay; + const nsStyleDisplay* childDisplay; childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - aCount++; - else if (aDeepCount && NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) { - PRInt32 childRowGroupCount; - ((nsTableRowGroupFrame*)childFrame)->GetRowCount(childRowGroupCount); - aCount += childRowGroupCount; - } + count++; GetNextFrame(childFrame, &childFrame); } - return NS_OK; + return count; } PRInt32 nsTableRowGroupFrame::GetStartRowIndex() { PRInt32 result = -1; - nsIFrame *childFrame = GetFirstFrame(); - while (PR_TRUE) - { - if (nsnull==childFrame) + nsIFrame* childFrame = GetFirstFrame(); + while (PR_TRUE) { + if (!childFrame) break; const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { result = ((nsTableRowFrame *)childFrame)->GetRowIndex(); break; } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) { - result = ((nsTableRowGroupFrame*)childFrame)->GetStartRowIndex(); - if (result != -1) - break; - } - GetNextFrame(childFrame, &childFrame); } // if the row group doesn't have any children, get it the hard way @@ -262,9 +248,9 @@ nsTableRowGroupFrame::GetSkipSides() const // aDirtyRect is in our coordinate system // child rect's are also in our coordinate system -/** overloaded method from nsContainerFrame. The difference is that - * we don't want to clip our children, so a cell can do a rowspan - */ +// overloaded method from nsContainerFrame. The difference is that +// we don't want to clip our children, so a cell can do a rowspan + void nsTableRowGroupFrame::PaintChildren(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -311,112 +297,69 @@ nsTableRowGroupFrame::GetFrameForPoint(nsIPresContext* aPresContext, // Position and size aKidFrame and update our reflow state. The origin of // aKidRect is relative to the upper-left origin of our frame -void nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext, - RowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize, - nscoord aX, - nscoord aY, - nsSize* aMaxElementSize, - nsSize& aKidMaxElementSize) +void +nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext, + nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame, + nsHTMLReflowMetrics& aDesiredSize) { // Place and size the child - FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, aX, aY, 0); + FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, 0, aReflowState.y, 0); // Adjust the running y-offset aReflowState.y += aDesiredSize.height; // If our height is constrained then update the available height - if (PR_FALSE == aReflowState.unconstrainedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) { aReflowState.availSize.height -= aDesiredSize.height; } - - // Update the maximum element size - if (PR_TRUE==aReflowState.firstRow) - { - aReflowState.firstRow = PR_FALSE; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = aKidMaxElementSize.width; - aMaxElementSize->height = aKidMaxElementSize.height; - } - } - else if (nsnull != aMaxElementSize) { - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, aKidMaxElementSize.width); - } } -/** - * Reflow the frames we've already created - * - * @param aPresContext presentation context to use - * @param aReflowState 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 - */ -NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus, - nsTableRowFrame * aStartFrame, - nsReflowReason aReason, - PRBool aDoSiblings, - PRBool aDirtyOnly) +// Reflow the frames we've already created. If aDirtyOnly is set then only +// reflow dirty frames. This assumes that all of the dirty frames are contiguous. +NS_METHOD +nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus, + nsTableRowFrame* aStartFrame, + PRBool aDirtyOnly) { - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; - nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); if (NS_FAILED(rv) || !tableFrame) return rv; nscoord cellSpacingY = tableFrame->GetCellSpacingY(); - if (!ContinueReflow(nsnull, aPresContext, aReflowState.y, aReflowState.availSize.height)) - return rv; + nsIFrame* lastReflowedRow = nsnull; + PRBool adjustSiblings = PR_TRUE; + nsIFrame* kidFrame = (aStartFrame) ? aStartFrame : mFrames.FirstChild(); - nsIFrame* kidFrame; - if (nsnull==aStartFrame) { - kidFrame = GetFirstFrameForReflow(aPresContext); - ReflowBeforeRowLayout(aPresContext, aDesiredSize, aReflowState, aStatus, aReason); - } - else - kidFrame = aStartFrame; - - PRUint8 borderStyle = aReflowState.tableFrame->GetBorderCollapseStyle(); - - for ( ; nsnull != kidFrame; ) - { + for ( ; kidFrame; ) { // Get the frame state bits nsFrameState frameState; kidFrame->GetFrameState(&frameState); // See if we should only reflow the dirty child frames - PRBool doReflowChild = PR_TRUE; - if (aDirtyOnly) { - if ((frameState & NS_FRAME_IS_DIRTY) == 0) { - doReflowChild = PR_FALSE; - } + PRBool doReflowChild = PR_TRUE; + if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) { + doReflowChild = PR_FALSE; } // Reflow the row frame if (doReflowChild) { nsSize kidAvailSize(aReflowState.availSize); - if (0>=kidAvailSize.height) + if (0 >= kidAvailSize.height) kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet - nsHTMLReflowMetrics desiredSize(pKidMaxElementSize); - desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0; + nsHTMLReflowMetrics desiredSize(nsnull); + desiredSize.width = desiredSize.height = desiredSize.ascent = desiredSize.descent = 0; - // Reflow the child into the available space, giving it as much room as + // Reflow the child into the available space, giving it as much height as // it wants. We'll deal with splitting later after we've computed the row // heights, taking into account cells with row spans... kidAvailSize.height = NS_UNCONSTRAINEDSIZE; - nsReflowReason reason = aReason; - if (aDirtyOnly) { - if (frameState & NS_FRAME_FIRST_REFLOW) { - // Newly inserted frame - reason = eReflowReason_Initial; - } - } + nsReflowReason reason = (frameState & NS_FRAME_FIRST_REFLOW) + ? eReflowReason_Initial : aReflowState.reason; nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, kidAvailSize, reason); @@ -426,93 +369,59 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC kidReflowState.isTopOfPage = PR_FALSE; } - if (aReflowState.tableFrame->RowGroupsShouldBeConstrained()) { - // Only applies to the tree widget. - const nsStyleDisplay *rowDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay && - aReflowState.availSize.height != NS_UNCONSTRAINEDSIZE) { - kidReflowState.availableHeight = aReflowState.availSize.height; - } - } - rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, aReflowState.y, 0, aStatus); // Place the child nsRect kidRect (0, aReflowState.y, desiredSize.width, desiredSize.height); - PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, 0, - aReflowState.y, aDesiredSize.maxElementSize, kidMaxElementSize); - - /* if the table has collapsing borders, we need to reset the length of the shared vertical borders - * for the table and the cells that overlap this row - */ - if ((eReflowReason_Initial != aReflowState.reflowState.reason) && - (NS_STYLE_BORDER_COLLAPSE==borderStyle)) { - const nsStyleDisplay *childDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { - PRInt32 rowIndex = ((nsTableRowFrame*)kidFrame)->GetRowIndex(); - aReflowState.tableFrame->SetBorderEdgeLength(NS_SIDE_LEFT, - rowIndex, - kidRect.height); - aReflowState.tableFrame->SetBorderEdgeLength(NS_SIDE_RIGHT, - rowIndex, - kidRect.height); - PRInt32 colCount = aReflowState.tableFrame->GetColCount(); - PRInt32 colIndex = 0; - nsIFrame *cellFrame; - for (colIndex = 0; colIndex < colCount; colIndex++) { - cellFrame = aReflowState.tableFrame->GetCellInfoAt(rowIndex, colIndex); - if (cellFrame) { - const nsStyleDisplay *cellDisplay; - cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) { - ((nsTableCellFrame *)(cellFrame))->SetBorderEdgeLength(NS_SIDE_LEFT, - rowIndex, - kidRect.height); - ((nsTableCellFrame *)(cellFrame))->SetBorderEdgeLength(NS_SIDE_RIGHT, - rowIndex, - kidRect.height); - } - } - } + PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize); + aReflowState.y += cellSpacingY; + lastReflowedRow = kidFrame; + } else { + // were done reflowing, so see if we need to reposition the rows that follow + if (lastReflowedRow) { + if (tableFrame->NeedsReflow(aReflowState.reflowState)) { + adjustSiblings = PR_FALSE; + break; // don't bother if the table will reflow everything. } } - aReflowState.y += cellSpacingY; - } else { - // Adjust the running y-offset so we know where the next row should - // be placed - nsSize kidSize; - + // Adjust the running y-offset so we know where the next row should be placed + nsSize kidSize; kidFrame->GetSize(kidSize); aReflowState.y += kidSize.height + cellSpacingY; } - if (PR_FALSE==aDoSiblings) - break; - - if (!ContinueReflow(kidFrame, aPresContext, aReflowState.y, aReflowState.availSize.height)) - break; - - // Get the next child - GetNextFrameForReflow(aPresContext, kidFrame, &kidFrame); + kidFrame->GetNextSibling(&kidFrame); // Get the next child + } + + // adjust the rows after the ones that were reflowed + if (lastReflowedRow && adjustSiblings) { + nsIFrame* nextRow = nsnull; + lastReflowedRow->GetNextSibling(&nextRow); + if (nextRow) { + nsRect lastReflowedRect, nextRect; + lastReflowedRow->GetRect(lastReflowedRect); + nextRow->GetRect(nextRect); + nscoord deltaY = cellSpacingY + lastReflowedRect.YMost() - nextRect.y; + if (deltaY != 0) { + AdjustSiblingsAfterReflow(aPresContext, aReflowState, lastReflowedRow, deltaY); + } + } } - // Call our post-row reflow hook - ReflowAfterRowLayout(aPresContext, aDesiredSize, aReflowState, aStatus, aReason); return rv; } /** * Pull-up all the row frames from our next-in-flow */ -NS_METHOD nsTableRowGroupFrame::PullUpAllRowFrames(nsIPresContext* aPresContext) +NS_METHOD +nsTableRowGroupFrame::PullUpAllRowFrames(nsIPresContext* aPresContext) { if (mNextInFlow) { nsTableRowGroupFrame* nextInFlow = (nsTableRowGroupFrame*)mNextInFlow; - while (nsnull != nextInFlow) { + while (nextInFlow) { // Any frames on the next-in-flow's overflow list? nsIFrame* nextOverflowFrames = nextInFlow->GetOverflowFrames(aPresContext, PR_TRUE); @@ -540,7 +449,8 @@ NS_METHOD nsTableRowGroupFrame::PullUpAllRowFrames(nsIPresContext* aPresContext) return NS_OK; } -void nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame) +void +nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame) { if (!*aRowFrame) return; GetNextFrame(*aRowFrame, aRowFrame); @@ -589,9 +499,10 @@ AllocateSpecialHeight(nsIPresContext* aPresContext, * Actual row heights are ultimately determined by the table, when the table * height attribute is factored in. */ -void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState) +void +nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState) { nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); @@ -601,8 +512,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresCon nscoord cellSpacingY = tableFrame->GetCellSpacingY(); PRBool hasRowSpanningCell = PR_FALSE; - PRInt32 numRows; - GetRowCount(numRows, PR_FALSE); + PRInt32 numRows = GetRowCount(); // collect the current height of each row. rows which have 0 height because // they have no cells originating in them without rowspans > 1, are referred to as // special rows. The current height of a special row will be a negative number until @@ -804,14 +714,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresCon rowFrame->SetRect(aPresContext, rowBounds); if (movedFrame) { - // Make sure any views are positioned properly - nsIView* view; - rowFrame->GetView(aPresContext, &view); - if (view) { - nsContainerFrame::PositionFrameView(aPresContext, rowFrame, view); - } else { - nsContainerFrame::PositionChildViews(aPresContext, rowFrame); - } + nsTableFrame::RePositionViews(aPresContext, rowFrame); } } @@ -860,32 +763,18 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresCon // cells that span into it and no cells that span across it. That way // we don't have to deal with rowspans nsresult -nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, - RowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize, - nscoord aDeltaY) +nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, + nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame, + nscoord aDeltaY) { NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight, "we're not in galley mode"); nsIFrame* lastKidFrame = aKidFrame; - // Move the frames that follow aKidFrame by aDeltaY and update the max element - // size + // Move the frames that follow aKidFrame by aDeltaY nsIFrame* kidFrame; for (aKidFrame->GetNextSibling(&kidFrame); kidFrame; kidFrame->GetNextSibling(&kidFrame)) { - // Update the max element size - if (aMaxElementSize) { - const nsStyleDisplay *display; - aKidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) { - nsSize kidMaxElementSize; - ((nsTableRowFrame*)kidFrame)->GetMaxElementSize(kidMaxElementSize); - - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, kidMaxElementSize.width); - } - } - // Move the frame if we need to if (aDeltaY != 0) { nsPoint origin; @@ -895,6 +784,7 @@ nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContex origin.y += aDeltaY; kidFrame->MoveTo(aPresContext, origin.x, origin.y); + nsTableFrame::RePositionViews(aPresContext, kidFrame); } // Remember the last frame @@ -945,7 +835,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { #ifdef NS_DEBUG // Verify it doesn't already have a next-in-flow. The reason it should - // not already have a next-in-flow is that ReflowMappedChildren() reflows + // not already have a next-in-flow is that ReflowChildren() reflows // the row frames with an unconstrained available height nsIFrame* nextInFlow; rowFrame->GetNextInFlow(&nextInFlow); @@ -1078,24 +968,17 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, #endif nsresult rv=NS_OK; - // Initialize out parameter - if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = 0; - aDesiredSize.maxElementSize->height = 0; - } - - nsTableFrame *tableFrame=nsnull; + nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv)) - return rv; - else if (tableFrame == nsnull) - return NS_ERROR_NULL_POINTER; + if (!tableFrame) return NS_ERROR_NULL_POINTER; - RowGroupReflowState state(aPresContext, aReflowState, tableFrame); + nsRowGroupReflowState state(aReflowState, tableFrame); + PRBool haveDesiredHeight = PR_FALSE; if (eReflowReason_Incremental == aReflowState.reason) { rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus); - } else { + } + else { aStatus = NS_FRAME_COMPLETE; // Check for an overflow list @@ -1107,8 +990,8 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, // reflowing the frames we have, the problem is we don't know if we have // room left until after we call CalculateRowHeights()... PullUpAllRowFrames(aPresContext); - rv = ReflowMappedChildren(aPresContext, aDesiredSize, state, aStatus, - nsnull, aReflowState.reason, PR_TRUE); + rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus, + nsnull, PR_FALSE); // Return our desired rect aDesiredSize.width = aReflowState.availableWidth; @@ -1129,60 +1012,34 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, } SetRepeatable(repeatable); } - // account for scroll bars. XXX needs optimization/caching - if (nsnull != aDesiredSize.maxElementSize) { - nsIAtom* pseudoTag; - - mStyleContext->GetPseudoType(pseudoTag); - if (pseudoTag == nsLayoutAtoms::scrolledContentPseudo) { - nsIFrame* scrollFrame; - GetParent(&scrollFrame); - const nsStyleDisplay *display; - scrollFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if ((NS_STYLE_OVERFLOW_SCROLL == display->mOverflow) || - (NS_STYLE_OVERFLOW_AUTO == display->mOverflow)) { - float sbWidth, sbHeight; - nsCOMPtr dc; - aPresContext->GetDeviceContext(getter_AddRefs(dc)); - - dc->GetScrollBarDimensions(sbWidth, sbHeight); - aDesiredSize.maxElementSize->width += NSToCoordRound(sbWidth); - // If scrollbars are always visible then add in the hor sb height - if (NS_STYLE_OVERFLOW_SCROLL == display->mOverflow) { - aDesiredSize.maxElementSize->height += NSToCoordRound(sbHeight); - } - } - } - NS_IF_RELEASE(pseudoTag); - } - // shrink wrap rows to height of tallest cell in that row - PRBool isTableUnconstrainedReflow = NS_UNCONSTRAINEDSIZE == - aReflowState.parentReflowState->availableWidth; + PRBool isTableUnconstrainedReflow = + (NS_UNCONSTRAINEDSIZE == aReflowState.parentReflowState->availableWidth); - // Skip this step if possible. We can skip it if the table is going to be + // Avoid calling CalculateRowHeights. We can avoid it if the table is going to be // doing a pass 2 reflow. In the case where the table is getting an unconstrained // reflow, then we need to do this because the table will skip the pass 2 reflow, // but we need to correctly calculate the row group height and we can't if there // are row spans unless we do this step if ((eReflowReason_Initial != aReflowState.reason) || isTableUnconstrainedReflow) { CalculateRowHeights(aPresContext, aDesiredSize, aReflowState); + haveDesiredHeight = PR_TRUE; } // See if all the frames fit - if (aDesiredSize.height > aReflowState.availableHeight && - !tableFrame->RowGroupsShouldBeConstrained()) { + if (aDesiredSize.height > aReflowState.availableHeight) { // Nope, find a place to split the row group SplitRowGroup(aPresContext, aDesiredSize, aReflowState, tableFrame, aStatus); } } - // If we computed our max element element size, then cache it so we can return - // it later when asked - if (aDesiredSize.maxElementSize) { - mMaxElementSize = *aDesiredSize.maxElementSize; + // just set our width to what was available. The table will calculate the width and not use our value. + aDesiredSize.width = aReflowState.availableWidth; + if (!haveDesiredHeight) { + // calculate the height based on the rect of the last row + aDesiredSize.height = GetHeightOfRows(aPresContext); } - + #if defined DEBUG_TABLE_REFLOW | DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus); #endif @@ -1190,22 +1047,21 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, } -NS_METHOD nsTableRowGroupFrame::IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableRowGroupFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; // determine if this frame is the target or not - nsIFrame *target=nsnull; + nsIFrame* target = nsnull; rv = aReflowState.reflowState.reflowCommand->GetTarget(target); - if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target)) - { - if (this==target) + if (NS_SUCCEEDED(rv) && target) { + if (this == target) rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus); - else - { + else { // Get the next frame in the reflow chain nsIFrame* nextFrame; aReflowState.reflowState.reflowCommand->GetNext(nextFrame); @@ -1216,49 +1072,6 @@ NS_METHOD nsTableRowGroupFrame::IncrementalReflow(nsIPresContext* aPresContext, return rv; } -// Helper function. It marks the table frame as dirty and generates -// a reflow command -nsresult -nsTableRowGroupFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aTableFrame) -{ - nsFrameState frameState; - nsIFrame* tableParentFrame; - nsIReflowCommand* reflowCmd; - nsresult rv; - - // Mark the table frame as dirty - aTableFrame->GetFrameState(&frameState); - frameState |= NS_FRAME_IS_DIRTY; - aTableFrame->SetFrameState(frameState); - - // Target the reflow comamnd at its parent frame - aTableFrame->GetParent(&tableParentFrame); - rv = NS_NewHTMLReflowCommand(&reflowCmd, tableParentFrame, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - // Add the reflow command - rv = aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - - return rv; -} - -#if 0 - // Reflow the new frames. They're already marked dirty, so generate a reflow - // command that tells us to reflow our dirty child frames - nsIReflowCommand* reflowCmd; - - if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty))) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } -#endif - -// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -1268,16 +1081,14 @@ nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, // collect the new row frames in an array nsVoidArray rows; for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { - nsIAtom* frameType; - rowFrame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableRowFrame == frameType) { + nsCOMPtr frameType; + rowFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableRowFrame == frameType.get()) { rows.AppendElement(rowFrame); } - NS_IF_RELEASE(frameType); } - PRInt32 rowIndex; - GetRowCount(rowIndex); + PRInt32 rowIndex = GetRowCount(); // Append the frames to the sibling chain mFrames.AppendFrames(nsnull, aFrameList); @@ -1286,18 +1097,11 @@ nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsTableFrame::GetTableFrame(this, tableFrame); if (tableFrame) { tableFrame->AppendRows(*aPresContext, *this, rowIndex, rows); - - // Because the number of columns may have changed invalidate the column widths - tableFrame->InvalidateColumnWidths(); - // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames - nsIReflowCommand* reflowCmd; - - if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty))) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); + nsTableFrame::AppendDirtyReflowCommand(&aPresShell, this); + if (tableFrame->RowIsSpannedInto(rowIndex)) { + tableFrame->SetNeedStrategyInit(PR_TRUE); } } } @@ -1305,7 +1109,6 @@ nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, return NS_OK; } -// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -1316,18 +1119,18 @@ nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, // collect the new row frames in an array nsVoidArray rows; for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { - nsIAtom* frameType; - rowFrame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableRowFrame == frameType) { + nsCOMPtr frameType; + rowFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableRowFrame == frameType.get()) { rows.AppendElement(rowFrame); } - NS_IF_RELEASE(frameType); } // Insert the frames in the sibling chain mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - if (rows.Count() > 0) { + PRInt32 numRows = rows.Count(); + if (numRows > 0) { nsTableFrame* tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); if (tableFrame) { @@ -1337,27 +1140,16 @@ nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames - nsIReflowCommand* reflowCmd; - - if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty))) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); + nsTableFrame::AppendDirtyReflowCommand(&aPresShell, this); + if (tableFrame->RowIsSpannedInto(rowIndex) || + tableFrame->RowHasSpanningCells(rowIndex + numRows - 1)) { + tableFrame->SetNeedStrategyInit(PR_TRUE); } - - // Because the number of columns may have changed invalidate the column widths - tableFrame->InvalidateColumnWidths(); - - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } } - return NS_OK; } -// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -1367,69 +1159,54 @@ nsTableRowGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsTableFrame* tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); if (tableFrame) { - nsIAtom* frameType; - aOldFrame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableRowFrame == frameType) { - PRInt32 firstRowIndex = ((nsTableRowFrame *)aOldFrame)->GetRowIndex(); - - tableFrame->RemoveRows(*aPresContext, firstRowIndex, 1, PR_TRUE); - // Because the number of columns may have changed invalidate the column widths - tableFrame->InvalidateColumnWidths(); + nsCOMPtr frameType; + aOldFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableRowFrame == frameType.get()) { + // remove the rows from the table (and flag a rebalance) + tableFrame->RemoveRows(*aPresContext, (nsTableRowFrame &)*aOldFrame, 1, PR_TRUE); + // XXX this could be optimized (see nsTableFrame::RemoveRows) + tableFrame->SetNeedStrategyInit(PR_TRUE); // Because we haven't added any new frames we don't need to do a pass1 - // reflow. Just generate a reflow command so we reflow the table itself - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + // reflow. Just generate a reflow command so we reflow the table + nsTableFrame::AppendDirtyReflowCommand(&aPresShell, this); } - NS_IF_RELEASE(frameType); } mFrames.DestroyFrame(aPresContext, aOldFrame); return NS_OK; } -NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_FRAME_COMPLETE; nsIReflowCommand::ReflowType type; aReflowState.reflowState.reflowCommand->GetType(type); - nsIFrame *objectFrame; - aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame); - const nsStyleDisplay *childDisplay=nsnull; - if (nsnull!=objectFrame) - objectFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - switch (type) - { - case nsIReflowCommand::ReflowDirty: - // Reflow the dirty child frames. Typically this is newly added frames. - // XXX What we really should do is do a pass-1 reflow of newly added - // frames (only if necessary, i.e., the table isn't fixed layout), then - // see if column widtsh changed and decide whether to do the pass-2 reflow - // of just the dirty rows or have the table rebalance column widths and - // do a pass-2 reflow of all rows - rv = ReflowMappedChildren(aPresContext, aDesiredSize, aReflowState, aStatus, - nsnull, aReflowState.reflowState.reason, PR_TRUE, PR_TRUE); - // If any column widths have to change due to this, rebalance column widths. - // XXX need to calculate this, but for now just do it - aReflowState.tableFrame->InvalidateColumnWidths(); - break; - - case nsIReflowCommand::StyleChanged : - rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); - break; - - case nsIReflowCommand::ContentChanged : - NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - - default: - NS_NOTYETIMPLEMENTED("unexpected reflow command type"); - rv = NS_ERROR_NOT_IMPLEMENTED; - break; + switch (type) { + case nsIReflowCommand::ReflowDirty: { + nsRowGroupReflowState state(aReflowState); + state.reason = eReflowReason_Resize; + // Reflow the dirty child frames. Typically this is newly added frames. + rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus, + nsnull, PR_TRUE); + break; + } + case nsIReflowCommand::StyleChanged : + rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); + break; + case nsIReflowCommand::ContentChanged : + NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + default: + NS_NOTYETIMPLEMENTED("unexpected reflow command type"); + rv = NS_ERROR_NOT_IMPLEMENTED; + break; } // XXX If we have a next-in-flow, then we're not complete @@ -1439,44 +1216,42 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext, - nscoord& aResult) +nscoord +nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext) { nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv) || !tableFrame) return rv; + if (!tableFrame) return 0; - nscoord cellSpacingY = tableFrame->GetCellSpacingY(); + nscoord height = 0; - // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] - // and the rowgroup itself needs to be expanded by SUM(row height deltas) + // enumerate the rows and total their heights nsIFrame* rowFrame = nsnull; rv = FirstChild(aPresContext, nsnull, &rowFrame); - while ((NS_SUCCEEDED(rv)) && (nsnull!=rowFrame)) { + PRInt32 numRows = 0; + while ((NS_SUCCEEDED(rv)) && rowFrame) { const nsStyleDisplay* rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { nsRect rowRect; rowFrame->GetRect(rowRect); - aResult += rowRect.height; - } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { - ((nsTableRowGroupFrame*)rowFrame)->GetHeightOfRows(aPresContext, aResult); + height += rowRect.height; + numRows++; } GetNextFrame(rowFrame, &rowFrame); } - return NS_OK; + if (numRows > 1) { + height += (numRows - 1) * tableFrame->GetCellSpacingY(); // add in cell spacing + } + + return height; } // Recovers the reflow state to what it should be if aKidFrame is about -// to be reflowed. Restores the following: -// - availSize -// - y -// - firstRow +// to be reflowed. Restores availSize, y nsresult -nsTableRowGroupFrame::RecoverState(RowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize) +nsTableRowGroupFrame::RecoverState(nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame) { nsTableFrame* tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); @@ -1494,29 +1269,9 @@ nsTableRowGroupFrame::RecoverState(RowGroupReflowState& aReflowState, aReflowState.y += cellSpacingY + kidSize.height; // If our height is constrained then update the available height - if (PR_FALSE == aReflowState.unconstrainedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) { aReflowState.availSize.height -= kidSize.height; } - - // Update the maximum element size - if (aMaxElementSize) { - const nsStyleDisplay *display; - frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) { - // Get the row frame's cached max element size - nsSize kidMaxElementSize; - ((nsTableRowFrame*)frame)->GetMaxElementSize(kidMaxElementSize); - - if (aReflowState.firstRow) { - aMaxElementSize->width = kidMaxElementSize.width; - aMaxElementSize->height = kidMaxElementSize.height; - } else { - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, kidMaxElementSize.width); - } - } - } - - aReflowState.firstRow = PR_FALSE; } return NS_OK; @@ -1568,17 +1323,18 @@ GetLastRowSibling(nsIFrame* aRowFrame) return lastRowFrame; } -NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame) +NS_METHOD +nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame) { nsresult rv; // Recover the state as if aNextFrame is about to be reflowed - RecoverState(aReflowState, aNextFrame, aDesiredSize.maxElementSize); + RecoverState(aReflowState, aNextFrame); // Remember the old rect nsRect oldKidRect; @@ -1600,8 +1356,7 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresConte // Place the row frame nsRect kidRect(0, aReflowState.y, desiredSize.width, desiredSize.height); - PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize, 0, - aReflowState.y, aDesiredSize.maxElementSize, kidMaxElementSize); + PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize); // See if the table needs a reflow (e.g., if the column widths have // changed). If so, just return and don't bother adjusting the rows @@ -1638,7 +1393,6 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresConte // Adjust the frames that follow AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, - aDesiredSize.maxElementSize, desiredSize.height - oldKidRect.height); aDesiredSize.height = aReflowState.y; } @@ -1649,7 +1403,6 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresConte } else { // Adjust the frames that follow... AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, - aDesiredSize.maxElementSize, desiredSize.height - oldKidRect.height); // Now recalculate the row heights @@ -1665,7 +1418,7 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresConte } // Return our desired width - aDesiredSize.width = aReflowState.reflowState.availableWidth; + //aDesiredSize.width = aReflowState.reflowState.availableWidth; if (mNextInFlow) { aStatus = NS_FRAME_NOT_COMPLETE; @@ -1674,15 +1427,16 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresConte return rv; } -NS_METHOD nsTableRowGroupFrame::IR_StyleChanged(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_METHOD +nsTableRowGroupFrame::IR_StyleChanged(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here // XXX: we can optimize this when we know which style attribute changed - aReflowState.tableFrame->InvalidateFirstPassCache(); + aReflowState.tableFrame->SetNeedStrategyInit(PR_TRUE); return rv; } @@ -1756,7 +1510,8 @@ NS_IMETHODIMP nsTableRowGroupFrame::GetNumLines(PRInt32* aResult) { NS_ENSURE_ARG_POINTER(aResult); - return GetRowCount(*aResult); + *aResult = GetRowCount(); + return *aResult; // XXX should return NS_OK } NS_IMETHODIMP @@ -1768,8 +1523,11 @@ nsTableRowGroupFrame::GetDirection(PRBool* aIsRightToLeft) } NS_IMETHODIMP -nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber, nsIFrame** aFirstFrameOnLine, PRInt32* aNumFramesOnLine, - nsRect& aLineBounds, PRUint32* aLineFlags) +nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber, + nsIFrame** aFirstFrameOnLine, + PRInt32* aNumFramesOnLine, + nsRect& aLineBounds, + PRUint32* aLineFlags) { NS_ENSURE_ARG_POINTER(aFirstFrameOnLine); NS_ENSURE_ARG_POINTER(aNumFramesOnLine); @@ -1808,7 +1566,8 @@ nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber, nsIFrame** aFirstFrameOnLine, } NS_IMETHODIMP -nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, PRInt32* aLineNumberResult) +nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, + PRInt32* aLineNumberResult) { NS_ENSURE_ARG_POINTER(aFrame); NS_ENSURE_ARG_POINTER(aLineNumberResult); @@ -1820,7 +1579,8 @@ nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, PRInt32* aLineNumberR } NS_IMETHODIMP -nsTableRowGroupFrame::FindLineAt(nscoord aY, PRInt32* aLineNumberResult) +nsTableRowGroupFrame::FindLineAt(nscoord aY, + PRInt32* aLineNumberResult) { return NS_ERROR_NOT_IMPLEMENTED; } @@ -1837,11 +1597,14 @@ nsTableRowGroupFrame::CheckLineOrder(PRInt32 aLine, #endif // IBMBIDI NS_IMETHODIMP -nsTableRowGroupFrame::FindFrameAt(PRInt32 aLineNumber, nscoord aX, +nsTableRowGroupFrame::FindFrameAt(PRInt32 aLineNumber, + nscoord aX, #ifdef IBMBIDI - PRBool aCouldBeReordered, + PRBool aCouldBeReordered, #endif // IBMBIDI - nsIFrame** aFrameFound, PRBool* aXIsBeforeFirstFrame, PRBool* aXIsAfterLastFrame) + nsIFrame** aFrameFound, + PRBool* aXIsBeforeFirstFrame, + PRBool* aXIsAfterLastFrame) { PRInt32 cellCount = 0; CellData* cellData; @@ -1912,7 +1675,8 @@ nsTableRowGroupFrame::FindFrameAt(PRInt32 aLineNumber, nscoord aX, } NS_IMETHODIMP -nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame, PRInt32 aLineNumber) +nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame, + PRInt32 aLineNumber) { NS_ENSURE_ARG_POINTER(aFrame); diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h index 3b49a898539..fbe1fe64e09 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h @@ -33,44 +33,30 @@ class nsTableRowFrame; class nsReflowTimer; #endif -/* ----------- RowGroupReflowState ---------- */ - -struct RowGroupReflowState { - nsIPresContext* mPresContext; // Our pres context +struct nsRowGroupReflowState { const nsHTMLReflowState& reflowState; // Our reflow state + nsTableFrame* tableFrame; + + nsReflowReason reason; + // The available size (computed from the parent) nsSize availSize; - // Flags for whether the max size is unconstrained - PRBool unconstrainedWidth; - PRBool unconstrainedHeight; - // Running y-offset nscoord y; - // Flag used to set maxElementSize to my first row - PRBool firstRow; - - nsTableFrame *tableFrame; - - RowGroupReflowState(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsTableFrame * aTableFrame) - : mPresContext(aPresContext), - reflowState(aReflowState) + nsRowGroupReflowState(const nsHTMLReflowState& aReflowState, + nsTableFrame* aTableFrame) + :reflowState(aReflowState), tableFrame(aTableFrame) { - availSize.width = reflowState.availableWidth; + availSize.width = reflowState.availableWidth; availSize.height = reflowState.availableHeight; - y=0; // border/padding??? - unconstrainedWidth = PRBool(reflowState.availableWidth == NS_UNCONSTRAINEDSIZE); - unconstrainedHeight = PRBool(reflowState.availableHeight == NS_UNCONSTRAINEDSIZE); - firstRow = PR_TRUE; - tableFrame = aTableFrame; + reason = reflowState.reason; + y = 0; } - ~RowGroupReflowState() { - } + ~nsRowGroupReflowState() {} }; #define NS_ITABLEROWGROUPFRAME_IID \ @@ -131,10 +117,10 @@ public: nsIFrame* aOldFrame); /** @see nsIFrame::Paint */ - NS_IMETHOD Paint(nsIPresContext* aPresContext, + NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsFramePaintLayer aWhichLayer); + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); /** ask all children to paint themselves, without clipping (for cells with rowspan>1) * @see nsIFrame::Paint @@ -160,10 +146,10 @@ public: * * @see nsIFrame::Reflow */ - NS_IMETHOD Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, + NS_IMETHOD Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); + nsReflowStatus& aStatus); /** * Get the "type" of the frame @@ -177,8 +163,8 @@ public: NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; #endif - /** set aCount to the number of child rows (not necessarily == number of child frames) */ - NS_METHOD GetRowCount(PRInt32 &aCount, PRBool aDeepCount = PR_TRUE); + /** return the number of child rows (not necessarily == number of child frames) */ + PRInt32 GetRowCount(); /** return the table-relative row index of the first row in this rowgroup. * if there are no rows, -1 is returned. @@ -201,14 +187,8 @@ public: /** * Get the total height of all the row rects */ - NS_METHOD GetHeightOfRows(nsIPresContext* aPresContext, nscoord& aResult); + nscoord GetHeightOfRows(nsIPresContext* aPresContext); - virtual PRBool RowGroupReceivesExcessSpace() { return PR_TRUE; } - - virtual PRBool ContinueReflow(nsIFrame* aFrame, nsIPresContext* aPresContext, nscoord y, nscoord height) { return PR_TRUE; } - - void GetMaxElementSize(nsSize& aMaxElementSize) const; - // nsILineIterator methods public: NS_IMETHOD GetNumLines(PRInt32* aResult); @@ -247,17 +227,13 @@ protected: /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; - void PlaceChild(nsIPresContext* aPresContext, - RowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize, - nscoord aX, - nscoord aY, - nsSize* aMaxElementSize, - nsSize& aKidMaxElementSize); + void PlaceChild(nsIPresContext* aPresContext, + nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame, + nsHTMLReflowMetrics& aDesiredSize); - void CalculateRowHeights(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, + void CalculateRowHeights(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState); @@ -268,36 +244,34 @@ protected: * * @see Reflow */ - NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus); - NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame); + NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame); - NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus); - NS_IMETHOD IR_StyleChanged(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_StyleChanged(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus); - nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, - RowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize, - nscoord aDeltaY); + nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, + nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame, + nscoord aDeltaY); - nsresult RecoverState(RowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsSize* aMaxElementSize); + nsresult RecoverState(nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame); /** * Reflow the frames we've already created @@ -307,14 +281,12 @@ protected: * @return true if we successfully reflowed all the mapped children and false * otherwise, e.g. we pushed children to the next in flow */ - NS_METHOD ReflowMappedChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus, - nsTableRowFrame * aStartFrame, - nsReflowReason aReason, - PRBool aDoSiblings, - PRBool aDirtyOnly = PR_FALSE); + NS_METHOD ReflowChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + nsRowGroupReflowState& aReflowState, + nsReflowStatus& aStatus, + nsTableRowFrame* aStartFrame, + PRBool aDirtyOnly = PR_FALSE); /** * Pull-up all the row frames from our next-in-flow @@ -327,50 +299,25 @@ protected: nsTableFrame* aTableFrame, nsReflowStatus& aStatus); - NS_IMETHOD ReflowBeforeRowLayout(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus, - nsReflowReason aReason) { return NS_OK; }; + PRBool IsSimpleRowFrame(nsTableFrame* aTableFrame, + nsIFrame* aFrame); - NS_IMETHOD ReflowAfterRowLayout(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - RowGroupReflowState& aReflowState, - nsReflowStatus& aStatus, - nsReflowReason aReason) { return NS_OK; }; - - nsresult AddTableDirtyReflowCommand(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aTableFrame); - - PRBool IsSimpleRowFrame(nsTableFrame* aTableFrame, nsIFrame* aFrame); - - virtual nsIFrame* GetFirstFrameForReflow(nsIPresContext* aPresContext) { return mFrames.FirstChild(); }; - virtual void GetNextFrameForReflow(nsIPresContext* aPresContext, nsIFrame* aFrame, nsIFrame** aResult) { aFrame->GetNextSibling(aResult); }; void GetNextRowSibling(nsIFrame** aRowFrame); public: virtual nsIFrame* GetFirstFrame() { return mFrames.FirstChild(); }; virtual nsIFrame* GetLastFrame() { return mFrames.LastChild(); }; - virtual void GetNextFrame(nsIFrame* aFrame, nsIFrame** aResult) { aFrame->GetNextSibling(aResult); }; - virtual PRBool RowsDesireExcessSpace() { return PR_TRUE; }; - virtual PRBool RowGroupDesiresExcessSpace() { return PR_TRUE; }; + virtual void GetNextFrame(nsIFrame* aFrame, + nsIFrame** aResult) { aFrame->GetNextSibling(aResult); }; PRBool IsRepeatable(); void SetRepeatable(PRBool aRepeatable); -private: - nsSize mMaxElementSize; - #ifdef DEBUG_TABLE_REFLOW_TIMING public: nsReflowTimer* mTimer; #endif }; -inline void nsTableRowGroupFrame::GetMaxElementSize(nsSize& aMaxElementSize) const -{ - aMaxElementSize = mMaxElementSize; -} inline PRBool nsTableRowGroupFrame::IsRepeatable() { diff --git a/mozilla/layout/html/tests/table/core/captions1.html b/mozilla/layout/html/tests/table/core/captions1.html index 8c77e7f10f4..feb4cd6484a 100644 --- a/mozilla/layout/html/tests/table/core/captions1.html +++ b/mozilla/layout/html/tests/table/core/captions1.html @@ -3,23 +3,23 @@