Back to index

lightning-sunbird  0.9+nobinonly
nsTableOuterFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsTableOuterFrame.h"
00039 #include "nsTableFrame.h"
00040 #include "nsHTMLReflowCommand.h"
00041 #include "nsStyleContext.h"
00042 #include "nsStyleConsts.h"
00043 #include "nsPresContext.h"
00044 #include "nsIRenderingContext.h"
00045 #include "nsCSSRendering.h"
00046 #include "nsIContent.h"
00047 #include "nsVoidArray.h"
00048 #include "prinrval.h"
00049 #include "nsLayoutAtoms.h"
00050 #include "nsHTMLParts.h"
00051 #include "nsIPresShell.h"
00052 #ifdef ACCESSIBILITY
00053 #include "nsIAccessibilityService.h"
00054 #endif
00055 #include "nsIServiceManager.h"
00056 #include "nsIDOMNode.h"
00057 
00058 /* ----------- nsTableCaptionFrame ---------- */
00059 
00060 #define NS_TABLE_FRAME_CAPTION_LIST_INDEX 0
00061 #define NO_SIDE 100
00062 
00063 // caption frame
00064 nsTableCaptionFrame::nsTableCaptionFrame()
00065 {
00066   // shrink wrap 
00067   SetFlags(NS_BLOCK_SPACE_MGR);
00068 }
00069 
00070 nsTableCaptionFrame::~nsTableCaptionFrame()
00071 {
00072 }
00073 
00074 NS_IMETHODIMP
00075 nsTableOuterFrame::Destroy(nsPresContext* aPresContext)
00076 {
00077   mCaptionFrames.DestroyFrames(aPresContext);
00078   return nsHTMLContainerFrame::Destroy(aPresContext);
00079 }
00080 
00081 nsIAtom*
00082 nsTableCaptionFrame::GetType() const
00083 {
00084   return nsLayoutAtoms::tableCaptionFrame;
00085 }
00086 
00087 nsresult 
00088 NS_NewTableCaptionFrame(nsIPresShell* aPresShell, 
00089                         nsIFrame**    aNewFrame)
00090 {
00091   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00092   if (nsnull == aNewFrame) {
00093     return NS_ERROR_NULL_POINTER;
00094   }
00095   nsTableCaptionFrame* it = new (aPresShell) nsTableCaptionFrame;
00096   if (nsnull == it) {
00097     return NS_ERROR_OUT_OF_MEMORY;
00098   }
00099   *aNewFrame = it;
00100   return NS_OK;
00101 }
00102 
00103 /* ----------- nsTableOuterFrame ---------- */
00104 
00105 NS_IMPL_ADDREF_INHERITED(nsTableOuterFrame, nsHTMLContainerFrame)
00106 NS_IMPL_RELEASE_INHERITED(nsTableOuterFrame, nsHTMLContainerFrame)
00107 
00108 nsTableOuterFrame::nsTableOuterFrame()
00109 {
00110   mPriorAvailWidth = 0;
00111 #ifdef DEBUG_TABLE_REFLOW_TIMING
00112   mTimer = new nsReflowTimer(this);
00113 #endif
00114 }
00115 
00116 nsTableOuterFrame::~nsTableOuterFrame()
00117 {
00118 #ifdef DEBUG_TABLE_REFLOW_TIMING
00119   nsTableFrame::DebugReflowDone(this);
00120 #endif
00121 }
00122 
00123 nsresult nsTableOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00124 {
00125   if (NULL == aInstancePtr) {
00126     return NS_ERROR_NULL_POINTER;
00127   }
00128 
00129   if (aIID.Equals(NS_GET_IID(nsITableLayout))) 
00130   { // note there is no addref here, frames are not addref'd
00131     *aInstancePtr = (void*)(nsITableLayout*)this;
00132     return NS_OK;
00133   }
00134 
00135   return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
00136 }
00137 
00138 #ifdef ACCESSIBILITY
00139 NS_IMETHODIMP nsTableOuterFrame::GetAccessible(nsIAccessible** aAccessible)
00140 {
00141   nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
00142 
00143   if (accService) {
00144     return accService->CreateHTMLTableAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
00145   }
00146 
00147   return NS_ERROR_FAILURE;
00148 }
00149 #endif
00150 
00151 /* virtual */ PRBool
00152 nsTableOuterFrame::IsContainingBlock() const
00153 {
00154   return PR_FALSE;
00155 }
00156 
00157 NS_IMETHODIMP
00158 nsTableOuterFrame::Init(nsPresContext*  aPresContext,
00159                    nsIContent*           aContent,
00160                    nsIFrame*             aParent,
00161                    nsStyleContext*       aContext,
00162                    nsIFrame*             aPrevInFlow)
00163 {
00164   nsresult rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, 
00165                                            aContext, aPrevInFlow);
00166   if (NS_FAILED(rv) || !mStyleContext) return rv;
00167   
00168   // record that children that are ignorable whitespace should be excluded 
00169   mState |= NS_FRAME_EXCLUDE_IGNORABLE_WHITESPACE;
00170 
00171   return rv;
00172 }
00173 
00174 nsIFrame*
00175 nsTableOuterFrame::GetFirstChild(nsIAtom* aListName) const
00176 {
00177   if (nsLayoutAtoms::captionList == aListName) {
00178     return mCaptionFrames.FirstChild();
00179   }
00180   if (!aListName) {
00181     return mFrames.FirstChild();
00182   }
00183   return nsnull;
00184 }
00185 
00186 nsIAtom*
00187 nsTableOuterFrame::GetAdditionalChildListName(PRInt32 aIndex) const
00188 {
00189   if (aIndex == NS_TABLE_FRAME_CAPTION_LIST_INDEX) {
00190     return nsLayoutAtoms::captionList;
00191   }
00192   return nsnull;
00193 }
00194 
00195 NS_IMETHODIMP 
00196 nsTableOuterFrame::SetInitialChildList(nsPresContext* aPresContext,
00197                                        nsIAtom*        aListName,
00198                                        nsIFrame*       aChildList)
00199 {
00200   if (nsLayoutAtoms::captionList == aListName) {
00201     // the frame constructor already checked for table-caption display type
00202     mCaptionFrames.SetFrames(aChildList);
00203     mCaptionFrame  = mCaptionFrames.FirstChild();
00204   }
00205   else {
00206     NS_ASSERTION(!aListName, "wrong childlist");
00207     NS_ASSERTION(mFrames.IsEmpty(), "Frame leak!");
00208     mFrames.SetFrames(aChildList);
00209     mInnerTableFrame = nsnull;
00210     if (aChildList) {
00211       if (nsLayoutAtoms::tableFrame == aChildList->GetType()) {
00212         mInnerTableFrame = (nsTableFrame*)aChildList;
00213       }
00214     }
00215   }
00216 
00217   return NS_OK;
00218 }
00219 
00220 NS_IMETHODIMP
00221 nsTableOuterFrame::AppendFrames(nsIAtom*        aListName,
00222                                 nsIFrame*       aFrameList)
00223 {
00224   nsresult rv;
00225 
00226   // We only have two child frames: the inner table and a caption frame.
00227   // The inner frame is provided when we're initialized, and it cannot change
00228   if (nsLayoutAtoms::captionList == aListName) {
00229     mCaptionFrames.AppendFrames(this, aFrameList);
00230     mCaptionFrame = mCaptionFrames.FirstChild();
00231 
00232     // Reflow the new caption frame. It's already marked dirty, so generate a reflow
00233     // command that tells us to reflow our dirty child frames
00234     rv = GetPresContext()->
00235         PresShell()->AppendReflowCommand(this, eReflowType_ReflowDirty,
00236                                            nsnull);
00237     
00238   }
00239   else {
00240     NS_PRECONDITION(PR_FALSE, "unexpected child frame type");
00241     rv = NS_ERROR_UNEXPECTED;
00242   }
00243 
00244   return rv;
00245 }
00246 
00247 NS_IMETHODIMP
00248 nsTableOuterFrame::InsertFrames(nsIAtom*        aListName,
00249                                 nsIFrame*       aPrevFrame,
00250                                 nsIFrame*       aFrameList)
00251 {
00252   if (nsLayoutAtoms::captionList == aListName) {
00253     mCaptionFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
00254     mCaptionFrame = mCaptionFrames.FirstChild();
00255 
00256     // Reflow the new caption frame. It's already marked dirty, so
00257     // just tell the pres shell.
00258     return GetPresContext()->
00259         PresShell()->AppendReflowCommand(this, eReflowType_ReflowDirty,
00260                                            nsnull);
00261   }
00262   else {
00263     NS_PRECONDITION(!aPrevFrame, "invalid previous frame");
00264     return AppendFrames(aListName, aFrameList);
00265   }
00266 }
00267 
00268 NS_IMETHODIMP
00269 nsTableOuterFrame::RemoveFrame(nsIAtom*        aListName,
00270                                nsIFrame*       aOldFrame)
00271 {
00272   // We only have two child frames: the inner table and one caption frame.
00273   // The inner frame can't be removed so this should be the caption
00274   NS_PRECONDITION(nsLayoutAtoms::captionList == aListName, "can't remove inner frame");
00275 
00276   PRUint8 captionSide = GetCaptionSide();
00277 
00278   // See if the (top/bottom) caption's minimum width impacted the inner table or there
00279   // is a left/right caption (that likely impacts the inner table)
00280   if ((mMinCaptionWidth == mRect.width) || 
00281       (NS_SIDE_LEFT == captionSide) || (NS_SIDE_RIGHT == captionSide)) {
00282     // The old caption width had an effect on the inner table width so
00283     // we're going to need to reflow it. Mark it dirty
00284     mInnerTableFrame->AddStateBits(NS_FRAME_IS_DIRTY);
00285   }
00286 
00287   // Remove the frame and destroy it
00288   mCaptionFrames.DestroyFrame(GetPresContext(), aOldFrame);
00289   mCaptionFrame = mCaptionFrames.FirstChild();
00290   
00291   mMinCaptionWidth = 0;
00292 
00293   // Generate a reflow command so we get reflowed
00294   GetPresContext()->PresShell()->AppendReflowCommand(this,
00295                                                      eReflowType_ReflowDirty,
00296                                                      nsnull);
00297 
00298   return NS_OK;
00299 }
00300 
00301 NS_METHOD 
00302 nsTableOuterFrame::Paint(nsPresContext*      aPresContext,
00303                          nsIRenderingContext& aRenderingContext,
00304                          const nsRect&        aDirtyRect,
00305                          nsFramePaintLayer    aWhichLayer,
00306                          PRUint32             aFlags)
00307 {
00308 #ifdef DEBUG
00309   // for debug...
00310   if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
00311     aRenderingContext.SetColor(NS_RGB(255,0,0));
00312     aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
00313   }
00314 #endif
00315   PRBool isVisible;
00316   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_FALSE, &isVisible)) && !isVisible) {
00317     return NS_OK;
00318   }
00319 
00320   // the remaining code was copied from nsContainerFrame::PaintChildren since
00321   // it only paints the primary child list
00322 
00323 
00324   // Child elements have the opportunity to override the visibility property
00325   // of their parent and display even if the parent is hidden
00326   
00327   // If overflow is hidden then set the clip rect so that children
00328   // don't leak out of us
00329   PRBool clip = GetStyleDisplay()->IsTableClip();
00330   if (clip) {
00331     aRenderingContext.PushState();
00332     SetOverflowClipRect(aRenderingContext);
00333   }
00334 
00335   if (mCaptionFrame) {
00336     PaintChild(aPresContext, aRenderingContext, aDirtyRect, mCaptionFrame, aWhichLayer);
00337   }
00338   for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
00339     PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid, aWhichLayer);
00340   }
00341 
00342   if (clip)
00343     aRenderingContext.PopState();
00344   
00345   return NS_OK;
00346 }
00347 
00348 NS_IMETHODIMP
00349 nsTableOuterFrame::GetFrameForPoint(const nsPoint& aPoint, 
00350                                    nsFramePaintLayer aWhichLayer,
00351                                    nsIFrame**     aFrame)
00352 {
00353   nsresult rv;
00354   
00355   // caption frames live in a different list which we need to check separately
00356   if (mCaptionFrame) {
00357     rv = GetFrameForPointUsing(aPoint, nsLayoutAtoms::captionList, aWhichLayer, PR_FALSE, aFrame);
00358     if (NS_OK == rv) {
00359       return NS_OK;
00360     }
00361   }
00362   // This frame should never get events (it contains the margins of the
00363   // table), so always pass |PR_FALSE| for |aConsiderSelf|.
00364   return GetFrameForPointUsing(aPoint, nsnull, aWhichLayer, PR_FALSE, aFrame);
00365 }
00366 
00367 NS_IMETHODIMP nsTableOuterFrame::SetSelected(nsPresContext* aPresContext,
00368                                              nsIDOMRange *aRange,
00369                                              PRBool aSelected,
00370                                              nsSpread aSpread)
00371 {
00372   nsresult result = nsFrame::SetSelected(aPresContext, aRange,aSelected, aSpread);
00373   if (NS_SUCCEEDED(result) && mInnerTableFrame)
00374     return mInnerTableFrame->SetSelected(aPresContext, aRange,aSelected, aSpread);
00375   return result;
00376 }
00377 
00378 NS_IMETHODIMP 
00379 nsTableOuterFrame::GetParentStyleContextFrame(nsPresContext* aPresContext,
00380                                               nsIFrame**      aProviderFrame,
00381                                               PRBool*         aIsChild)
00382 {
00383   // The table outer frame and the (inner) table frame split the style
00384   // data by giving the table frame the style context associated with
00385   // the table content node and creating a style context for the outer
00386   // frame that is a *child* of the table frame's style context,
00387   // matching the ::-moz-table-outer pseudo-element.  html.css has a
00388   // rule that causes that pseudo-element (and thus the outer table)
00389   // to inherit *some* style properties from the table frame.  The
00390   // children of the table inherit directly from the inner table, and
00391   // the outer table's style context is a leaf.
00392 
00393   if (!mInnerTableFrame) {
00394     *aProviderFrame = this;
00395     *aIsChild = PR_FALSE;
00396     return NS_ERROR_FAILURE;
00397   }
00398   *aProviderFrame = mInnerTableFrame;
00399   *aIsChild = PR_TRUE;
00400   return NS_OK;
00401 }
00402 
00403 // INCREMENTAL REFLOW HELPER FUNCTIONS 
00404 
00405 void
00406 nsTableOuterFrame::ZeroAutoMargin(nsHTMLReflowState& aReflowState,
00407                                   nsMargin&          aMargin)
00408 {
00409   if (eStyleUnit_Auto == aReflowState.mStyleMargin->mMargin.GetLeftUnit()) {
00410     aMargin.left = 0;
00411   }
00412   if (eStyleUnit_Auto == aReflowState.mStyleMargin->mMargin.GetRightUnit()) {
00413     aMargin.right = 0;
00414   }
00415 }
00416 
00417 static void 
00418 FixAutoMargins(nscoord            aAvailWidth,
00419                nscoord            aChildWidth,
00420                nsHTMLReflowState& aReflowState)
00421 {
00422   // see if there are auto margins. they may have been set to 0 in mComputedMargin
00423   PRBool hasAutoMargin = eStyleUnit_Auto == aReflowState.mStyleMargin->mMargin.GetLeftUnit() ||
00424                          eStyleUnit_Auto == aReflowState.mStyleMargin->mMargin.GetRightUnit();
00425   if (hasAutoMargin) {
00426     nscoord width = aChildWidth;
00427     if (NS_UNCONSTRAINEDSIZE == width) {
00428       width = 0;
00429     }
00430     aReflowState.CalculateBlockSideMargins(aAvailWidth, width);
00431   }
00432 }
00433 
00434 void
00435 nsTableOuterFrame::InitChildReflowState(nsPresContext&    aPresContext,                     
00436                                         nsHTMLReflowState& aReflowState)
00437                                     
00438 {
00439   nsMargin collapseBorder;
00440   nsMargin collapsePadding(0,0,0,0);
00441   nsMargin* pCollapseBorder  = nsnull;
00442   nsMargin* pCollapsePadding = nsnull;
00443   if ((aReflowState.frame == mInnerTableFrame) && (mInnerTableFrame->IsBorderCollapse())) {
00444     if (mInnerTableFrame->NeedToCalcBCBorders()) {
00445       mInnerTableFrame->CalcBCBorders();
00446     }
00447     collapseBorder  = mInnerTableFrame->GetBCBorder();
00448     pCollapseBorder = &collapseBorder;
00449     pCollapsePadding = &collapsePadding;
00450   }
00451   aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, pCollapsePadding);
00452 }
00453 
00454 // get the margin and padding data. nsHTMLReflowState doesn't handle the
00455 // case of auto margins
00456 void
00457 nsTableOuterFrame::GetMarginPadding(nsPresContext*          aPresContext,                     
00458                                     const nsHTMLReflowState& aOuterRS,
00459                                     nsIFrame*                aChildFrame,
00460                                     nscoord                  aAvailWidth, 
00461                                     nsMargin&                aMargin,
00462                                     nsMargin&                aMarginNoAuto,
00463                                     nsMargin&                aPadding)
00464 {
00465   // construct a reflow state to compute margin and padding. Auto margins
00466   // will not be computed at this time.
00467 
00468   // create and init the child reflow state
00469   nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, 
00470                             nsSize(aAvailWidth, aOuterRS.availableHeight), 
00471                             eReflowReason_Resize, PR_FALSE);
00472   InitChildReflowState(*aPresContext, childRS);
00473 
00474   FixAutoMargins(aAvailWidth, aChildFrame->GetSize().width, childRS); 
00475   aMargin = childRS.mComputedMargin;
00476   aMarginNoAuto = aMargin;
00477   nsTableOuterFrame::ZeroAutoMargin(childRS, aMarginNoAuto);
00478 
00479   aPadding = childRS.mComputedPadding;
00480 }
00481 
00482 static
00483 nscoord CalcAutoMargin(nscoord aAutoMargin,
00484                        nscoord aOppositeMargin,
00485                        nscoord aContainBlockSize,
00486                        nscoord aFrameSize,
00487                        float   aPixelToTwips)
00488 {
00489   nscoord margin;
00490   if (NS_AUTOMARGIN == aOppositeMargin) 
00491     margin = nsTableFrame::RoundToPixel((aContainBlockSize - aFrameSize) / 2, aPixelToTwips);
00492   else {
00493     margin = aContainBlockSize - aFrameSize - aOppositeMargin;
00494   }
00495   return PR_MAX(0, margin);
00496 }
00497 
00498 static void
00499 MoveFrameTo(nsIFrame* aFrame, 
00500             nscoord   aX,
00501             nscoord   aY)
00502 {
00503   nsPoint pt = aFrame->GetPosition();
00504   if ((pt.x != aX) || (pt.y != aY)) {
00505     aFrame->SetPosition(nsPoint(aX, aY));
00506     nsTableFrame::RePositionViews(aFrame);
00507   }
00508 }
00509 
00510 static nsSize
00511 GetContainingBlockSize(const nsHTMLReflowState& aOuterRS)
00512 {
00513   nsSize size(0,0);
00514   const nsHTMLReflowState* containRS =
00515     aOuterRS.mCBReflowState;
00516 
00517   if (containRS) {
00518     size.width = containRS->mComputedWidth;
00519     if (NS_UNCONSTRAINEDSIZE == size.width) {
00520       size.width = 0;
00521     }
00522     size.height = containRS->mComputedHeight;
00523     if (NS_UNCONSTRAINEDSIZE == size.height) {
00524       size.height = 0;
00525     }
00526   }
00527   return size;
00528 }
00529 
00530 void
00531 nsTableOuterFrame::InvalidateDamage(PRUint8         aCaptionSide,
00532                                     const nsSize&   aOuterSize,
00533                                     PRBool          aInnerChanged,
00534                                     PRBool          aCaptionChanged,
00535                                     nsRect*         aOldOverflowArea)
00536 {
00537   if (!aInnerChanged && !aCaptionChanged) return;
00538 
00539   nsRect damage;
00540   if (aInnerChanged && aCaptionChanged) {
00541     damage = nsRect(0, 0, aOuterSize.width, aOuterSize.height);
00542     if (aOldOverflowArea) {
00543       damage.UnionRect(damage, *aOldOverflowArea);
00544     }
00545     nsRect* overflowArea = GetOverflowAreaProperty();
00546     if (overflowArea) {
00547       damage.UnionRect(damage, *overflowArea);
00548     }
00549   }
00550   else {
00551     nsRect captionRect(0,0,0,0);
00552     nsRect innerRect = mInnerTableFrame->GetRect();
00553     if (mCaptionFrame) {
00554       captionRect = mCaptionFrame->GetRect();
00555     }
00556     
00557     damage.x = 0;
00558     damage.width  = aOuterSize.width;
00559     switch(aCaptionSide) {
00560     case NS_SIDE_BOTTOM:
00561       if (aCaptionChanged) {
00562         damage.y = innerRect.y;
00563         damage.height = aOuterSize.height - damage.y;
00564       }
00565       else { // aInnerChanged 
00566         damage.y = 0;
00567         damage.height = captionRect.y;
00568       }
00569       break;
00570     case NS_SIDE_LEFT:
00571       if (aCaptionChanged) {
00572         damage.width = innerRect.x;
00573         damage.y = 0;
00574         damage.height = captionRect.YMost();
00575       }
00576       else { // aInnerChanged
00577         damage.x = captionRect.XMost();
00578         damage.width = innerRect.XMost() - damage.x;
00579         damage.y = 0;
00580         damage.height = innerRect.YMost();
00581       }
00582       break;
00583     case NS_SIDE_RIGHT:
00584      if (aCaptionChanged) {
00585         damage.x = innerRect.XMost();
00586         damage.width -= damage.x;
00587         damage.y = 0;
00588         damage.height = captionRect.YMost();
00589       }
00590      else { // aInnerChanged
00591         damage.width -= captionRect.width;
00592         damage.y = 0;
00593         damage.height = innerRect.YMost();
00594       }
00595       break;
00596     default: // NS_SIDE_TOP
00597       if (aCaptionChanged) {
00598         damage.y = 0;
00599         damage.height = innerRect.y;
00600       }
00601       else { // aInnerChanged
00602         damage.y = captionRect.y;
00603         damage.height = aOuterSize.height - damage.y;
00604       }
00605       break;
00606     }
00607      
00608     nsIFrame* kidFrame = aCaptionChanged ? mCaptionFrame : mInnerTableFrame;
00609     ConsiderChildOverflow(damage, kidFrame);
00610     if (aOldOverflowArea) {
00611       damage.UnionRect(damage, *aOldOverflowArea);
00612     }
00613   }
00614   Invalidate(damage);
00615 }
00616 
00617 nscoord
00618 nsTableOuterFrame::GetCaptionAvailWidth(nsPresContext*          aPresContext,
00619                                         nsIFrame*                aCaptionFrame,
00620                                         const nsHTMLReflowState& aOuterRS,
00621                                         nsMargin&                aCaptionMargin,
00622                                         nsMargin&                aCaptionPad,
00623                                         nscoord*                 aInnerWidth,
00624                                         const nsMargin*          aInnerMarginNoAuto,
00625                                         const nsMargin*          aInnerMargin)
00626 {
00627   nscoord availWidth;
00628   if (aInnerWidth) {
00629     nscoord innerWidth = *aInnerWidth;
00630     if (NS_UNCONSTRAINEDSIZE == innerWidth) {
00631       availWidth = innerWidth;
00632     }
00633     else {
00634       nsMargin innerMarginNoAuto(0,0,0,0);
00635       if (aInnerMarginNoAuto) {
00636         innerMarginNoAuto = *aInnerMarginNoAuto;
00637       }
00638       nsMargin innerMargin(0,0,0,0);
00639       if (aInnerMargin) {
00640         innerMargin = *aInnerMargin;
00641       }
00642       PRUint8 captionSide = GetCaptionSide();
00643       switch (captionSide) {
00644         case NS_SIDE_LEFT: 
00645         case NS_SIDE_RIGHT:
00646           availWidth = (NS_SIDE_LEFT == captionSide) ? innerMargin.left : innerMargin.right;
00647           break;
00648         default: // NS_SIDE_TOP, NS_SIDE_BOTTOM
00649           availWidth = innerWidth + innerMarginNoAuto.left + innerMarginNoAuto.right;
00650           break;
00651       }
00652     }
00653   }
00654   else {
00655     availWidth = GetSize().width;
00656   }
00657 
00658   if (NS_UNCONSTRAINEDSIZE == availWidth) {
00659     return availWidth;
00660   }
00661   else {
00662     nsMargin marginIgnore;
00663     GetMarginPadding(aPresContext, aOuterRS, aCaptionFrame, availWidth, 
00664                      marginIgnore, aCaptionMargin, aCaptionPad);
00665     availWidth -= aCaptionMargin.left + aCaptionMargin.right;
00666     return (PR_MAX(availWidth, mMinCaptionWidth));
00667   }
00668 }
00669 
00670 nscoord
00671 nsTableOuterFrame::GetInnerTableAvailWidth(nsPresContext*          aPresContext,
00672                                            nsIFrame*                aInnerTable,
00673                                            const nsHTMLReflowState& aOuterRS,
00674                                            nscoord*                 aCaptionWidth,
00675                                            nsMargin&                aInnerMargin,
00676                                            nsMargin&                aInnerPadding)
00677 {
00678   nscoord availWidth;
00679   nscoord captionWidth = 0;
00680   if (aCaptionWidth) {
00681     captionWidth = *aCaptionWidth;
00682     if (NS_UNCONSTRAINEDSIZE == captionWidth) {
00683       availWidth = captionWidth;
00684     }
00685     else {
00686       availWidth = aOuterRS.availableWidth;
00687     }
00688   }
00689   else {
00690     availWidth = GetSize().width;
00691   }
00692 
00693   if (NS_UNCONSTRAINEDSIZE == availWidth) {
00694     return availWidth;
00695   }
00696   else {
00697     nsMargin marginIgnore;
00698     GetMarginPadding(aPresContext, aOuterRS, aInnerTable, availWidth, marginIgnore, aInnerMargin, aInnerPadding);
00699     availWidth -= aInnerMargin.left + aInnerMargin.right;
00700     PRUint8 captionSide = GetCaptionSide();
00701     switch (captionSide) {
00702       case NS_SIDE_LEFT:
00703         if (captionWidth > marginIgnore.left) {
00704           availWidth -= captionWidth - aInnerMargin.left;
00705         }
00706         break;
00707       case NS_SIDE_RIGHT:
00708         if (captionWidth > marginIgnore.right) {
00709           availWidth -= captionWidth - aInnerMargin.right;
00710         }
00711         break;
00712       default:
00713         availWidth = PR_MAX(availWidth, mMinCaptionWidth);
00714         break;
00715     }
00716     return(availWidth);
00717   }
00718 }
00719 
00720 nscoord
00721 nsTableOuterFrame::GetMaxElementWidth(PRUint8         aCaptionSide,
00722                                       const nsMargin& aInnerMargin,
00723                                       const nsMargin& aInnerPadding,
00724                                       const nsMargin& aCaptionMargin)
00725 {
00726   nscoord width = aInnerMargin.left + 
00727                   ((nsTableFrame *)mInnerTableFrame)->GetMinWidth() + 
00728                   aInnerMargin.right;
00729   if (mCaptionFrame) { 
00730     nscoord capWidth = mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right;
00731     switch(aCaptionSide) {
00732     case NS_SIDE_LEFT:
00733       if (capWidth > aInnerMargin.left) {
00734         width += capWidth - aInnerMargin.left;
00735       }
00736       break;
00737     case NS_SIDE_RIGHT:
00738       if (capWidth > aInnerMargin.right) {
00739         width += capWidth - aInnerMargin.right;
00740       }
00741       break;
00742     default:
00743       if (capWidth > width) {
00744         width = capWidth;
00745       }
00746     }
00747   }
00748   return width;
00749 }
00750 
00751 nscoord
00752 nsTableOuterFrame::GetMaxWidth(PRUint8         aCaptionSide,
00753                                const nsMargin& aInnerMargin,
00754                                const nsMargin& aCaptionMargin)
00755 {
00756   nscoord maxWidth;
00757 
00758   maxWidth = ((nsTableFrame *)mInnerTableFrame)->GetPreferredWidth() + 
00759                aInnerMargin.left + aInnerMargin.right;
00760   if (mCaptionFrame) {
00761     switch(aCaptionSide) {
00762     case NS_SIDE_LEFT:
00763     case NS_SIDE_RIGHT:
00764       maxWidth += mCaptionFrame->GetSize().width + aCaptionMargin.left + aCaptionMargin.right;
00765       // the caption plus it margins should cover the corresponding inner table side
00766       // margin - don't count it twice.
00767       maxWidth -= (NS_SIDE_LEFT == aCaptionSide) ? aInnerMargin.left : aInnerMargin.right;
00768       break;
00769     case NS_SIDE_TOP:
00770     case NS_SIDE_BOTTOM:
00771     default:  // no caption 
00772       maxWidth = PR_MAX(maxWidth, mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right);
00773     }
00774   }
00775   return maxWidth;
00776 }
00777 
00778 
00779 PRUint8
00780 nsTableOuterFrame::GetCaptionSide()
00781 {
00782   if (mCaptionFrame) {
00783     return mCaptionFrame->GetStyleTableBorder()->mCaptionSide;
00784   }
00785   else {
00786     return NO_SIDE; // no caption
00787   }
00788 }
00789 
00790 PRUint8
00791 nsTableOuterFrame::GetCaptionVerticalAlign()
00792 {
00793   const nsStyleCoord& va = mCaptionFrame->GetStyleTextReset()->mVerticalAlign;
00794   return (va.GetUnit() == eStyleUnit_Enumerated)
00795            ? va.GetIntValue()
00796            : NS_STYLE_VERTICAL_ALIGN_TOP;
00797 }
00798 
00799 void
00800 nsTableOuterFrame::SetDesiredSize(PRUint8         aCaptionSide,
00801                                   const nsMargin& aInnerMargin,
00802                                   const nsMargin& aCaptionMargin,
00803                                   nscoord         aAvailableWidth,
00804                                   nscoord&        aWidth,
00805                                   nscoord&        aHeight)
00806 {
00807   aWidth = aHeight = 0;
00808 
00809   nsRect innerRect = mInnerTableFrame->GetRect();
00810   nscoord innerWidth = innerRect.width;
00811 
00812   nsRect captionRect(0,0,0,0);
00813   nscoord captionWidth = 0;
00814   if (mCaptionFrame) {
00815     captionRect = mCaptionFrame->GetRect();
00816     captionWidth = captionRect.width;
00817     if ((NS_UNCONSTRAINEDSIZE == aAvailableWidth) &&
00818         ((NS_SIDE_LEFT == aCaptionSide) || (NS_SIDE_RIGHT == aCaptionSide))) {
00819       BalanceLeftRightCaption(aCaptionSide, aInnerMargin, aCaptionMargin, 
00820                               innerWidth, captionWidth);
00821     }
00822   }
00823   switch(aCaptionSide) {
00824     case NS_SIDE_LEFT:
00825       aWidth = PR_MAX(aInnerMargin.left, aCaptionMargin.left + captionWidth + aCaptionMargin.right) +
00826                innerWidth + aInnerMargin.right;
00827       break;
00828     case NS_SIDE_RIGHT:
00829       aWidth = PR_MAX(aInnerMargin.right, aCaptionMargin.left + captionWidth + aCaptionMargin.right) +
00830                innerWidth + aInnerMargin.left;
00831       break;
00832     default:
00833       aWidth = aInnerMargin.left + innerWidth + aInnerMargin.right;
00834       aWidth = PR_MAX(aWidth, captionRect.XMost() + aCaptionMargin.right);
00835   }
00836   aHeight = innerRect.YMost() + aInnerMargin.bottom;
00837   aHeight = PR_MAX(aHeight, captionRect.YMost() + aCaptionMargin.bottom);
00838 
00839 }
00840 
00841 void 
00842 nsTableOuterFrame::PctAdjustMinCaptionWidth(nsPresContext*           aPresContext,
00843                                             const nsHTMLReflowState&  aOuterRS,
00844                                             PRUint8                   aCaptionSide,
00845                                             nscoord&                  capMin)
00846 {
00847   if (NS_SIDE_LEFT == aCaptionSide || NS_SIDE_RIGHT == aCaptionSide) {
00848     if (mCaptionFrame) {
00849       nsMargin capMarginIgnore;
00850       nsMargin capMarginNoAuto;
00851       nsMargin captionPaddingIgnore;
00852       GetMarginPadding(aPresContext, aOuterRS, mCaptionFrame, aOuterRS.availableWidth, capMarginIgnore, 
00853                        capMarginNoAuto, captionPaddingIgnore);
00854       PRBool isPctWidth;
00855       IsAutoWidth(*mCaptionFrame,&isPctWidth);
00856       if (isPctWidth) {
00857         capMin = mCaptionFrame->GetSize().width;
00858       }
00859       capMin += capMarginNoAuto.left + capMarginNoAuto.right;
00860     }
00861   }
00862 }
00863 void
00864 nsTableOuterFrame::BalanceLeftRightCaption(PRUint8         aCaptionSide,
00865                                            const nsMargin& aInnerMargin,
00866                                            const nsMargin& aCaptionMargin,
00867                                            nscoord&        aInnerWidth, 
00868                                            nscoord&        aCaptionWidth)
00869 {
00870   
00871   /* balance the caption and inner table widths to ensure space for percent widths
00872   *  Percent widths for captions or the inner table frame can determine how much of the
00873   *  available width is used and how the available width is distributed between those frames
00874   *  The inner table frame has already a quite sophisticated treatment of percentage widths 
00875   *  (see BasicTableLayoutStrategy.cpp). So it acts as master in the below computations.
00876   *  There are four possible scenarios 
00877   *  a) None of the frames have a percentage width - then the aInnerWidth and aCaptionwidth will not change
00878   *  b) Only the inner frame has a percentage width - this is handled in BasicTableLayoutStrategy.cpp, 
00879   *     both widths will not change
00880   *  c) Only the caption has a percentage width - then the overall width (ow) will be different depending on
00881   *     the caption side. For the left side
00882   *     ow = aCaptionMargin.left + aCaptionWidth + aCaptionMargin.right + aInnerwidth + aInnerMargin.right
00883   *     aCaptionWidth = capPercent * ow
00884   *     solving this equation for aCaptionWidth gives:
00885   *     aCaptionWidth = capPercent/(1-capPercent) * 
00886   *                      (aCaptionMargin.left + aCaptionMargin.right + aInnerwidth + aInnerMargin.right)
00887   *     this result will cause problems for capPercent >= 1, in these cases the algorithm will now bail out
00888   *     a similar expression can be found for the right case
00889   *  d) both frames have percent widths in this case the caption width will be the inner width multiplied 
00890   *     by the weight capPercent/innerPercent
00891   */
00892     
00893 
00894   float capPercent   = -1.0;
00895   float innerPercent = -1.0;
00896   const nsStylePosition* position = mCaptionFrame->GetStylePosition();
00897   if (eStyleUnit_Percent == position->mWidth.GetUnit()) {
00898     capPercent = position->mWidth.GetPercentValue();
00899     if (capPercent >= 1.0)
00900       return;
00901   }
00902 
00903   position = mInnerTableFrame->GetStylePosition();
00904   if (eStyleUnit_Percent == position->mWidth.GetUnit()) {
00905     innerPercent = position->mWidth.GetPercentValue();
00906     if (innerPercent >= 1.0)
00907       return;
00908   }
00909 
00910   if ((capPercent <= 0.0) && (innerPercent <= 0.0))
00911     return;
00912 
00913   
00914   if (innerPercent <= 0.0) {
00915     if (NS_SIDE_LEFT == aCaptionSide) 
00916       aCaptionWidth= (nscoord) ((capPercent / (1.0 - capPercent)) * (aCaptionMargin.left + aCaptionMargin.right + 
00917                                                           aInnerWidth + aInnerMargin.right));
00918     else
00919       aCaptionWidth= (nscoord) ((capPercent / (1.0 - capPercent)) * (aCaptionMargin.left + aCaptionMargin.right + 
00920                                                           aInnerWidth + aInnerMargin.left)); 
00921   } 
00922   else {
00923     aCaptionWidth = (nscoord) ((capPercent / innerPercent) * aInnerWidth);
00924   }
00925   aCaptionWidth = nsTableFrame::RoundToPixel(aCaptionWidth,
00926                                              GetPresContext()->ScaledPixelsToTwips(),
00927                                              eAlwaysRoundDown);
00928 }
00929 
00930 nsresult 
00931 nsTableOuterFrame::GetCaptionOrigin(nsPresContext*  aPresContext,
00932                                     PRUint32         aCaptionSide,
00933                                     const nsSize&    aContainBlockSize,
00934                                     const nsSize&    aInnerSize, 
00935                                     const nsMargin&  aInnerMargin,
00936                                     const nsSize&    aCaptionSize,
00937                                     nsMargin&        aCaptionMargin,
00938                                     nsPoint&         aOrigin)
00939 {
00940   aOrigin.x = aOrigin.y = 0;
00941   if ((NS_UNCONSTRAINEDSIZE == aInnerSize.width) || (NS_UNCONSTRAINEDSIZE == aInnerSize.height) ||  
00942       (NS_UNCONSTRAINEDSIZE == aCaptionSize.width) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.height)) {
00943     return NS_OK;
00944   }
00945   if (!mCaptionFrame) return NS_OK;
00946 
00947   float p2t = aPresContext->ScaledPixelsToTwips();
00948 
00949   switch(aCaptionSide) {
00950   case NS_SIDE_BOTTOM: {
00951     if (NS_AUTOMARGIN == aCaptionMargin.left) {
00952       aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right,
00953                                            aContainBlockSize.width, aCaptionSize.width, p2t);
00954     }
00955     aOrigin.x = aCaptionMargin.left;
00956     if (NS_AUTOMARGIN == aCaptionMargin.top) {
00957       aCaptionMargin.top = 0;
00958     }
00959     nsCollapsingMargin marg;
00960     marg.Include(aCaptionMargin.top);
00961     marg.Include(aInnerMargin.bottom);
00962     nscoord collapseMargin = marg.get();
00963     if (NS_AUTOMARGIN == aCaptionMargin.bottom) {
00964       nscoord height = aInnerSize.height + collapseMargin + aCaptionSize.height;
00965       aCaptionMargin.bottom = CalcAutoMargin(aCaptionMargin.bottom, aInnerMargin.top,
00966                                              aContainBlockSize.height, height, p2t);
00967     }
00968     aOrigin.y = aInnerMargin.top + aInnerSize.height + collapseMargin;
00969   } break;
00970   case NS_SIDE_LEFT: {
00971     if (NS_AUTOMARGIN == aCaptionMargin.left) {
00972       if (NS_AUTOMARGIN != aInnerMargin.left) {
00973         aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right,
00974                                              aInnerMargin.left, aCaptionSize.width, p2t);
00975       } 
00976       else {
00977         // zero for now
00978         aCaptionMargin.left = 0;
00979       } 
00980     }
00981     aOrigin.x = aCaptionMargin.left;
00982     aOrigin.y = aInnerMargin.top;
00983     switch(GetCaptionVerticalAlign()) {
00984       case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
00985         aOrigin.y = PR_MAX(0, aInnerMargin.top + ((aInnerSize.height - aCaptionSize.height) / 2));
00986         break;
00987       case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
00988         aOrigin.y = PR_MAX(0, aInnerMargin.top + aInnerSize.height - aCaptionSize.height);
00989         break;
00990       default:
00991         break;
00992     }
00993   } break;
00994   case NS_SIDE_RIGHT: {
00995     if (NS_AUTOMARGIN == aCaptionMargin.left) {
00996       if (NS_AUTOMARGIN != aInnerMargin.right) {
00997         aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right,
00998                                              aInnerMargin.right, aCaptionSize.width, p2t);
00999       }
01000       else {
01001        // zero for now
01002        aCaptionMargin.left = 0;
01003       } 
01004     }
01005     aOrigin.x = aInnerMargin.left + aInnerSize.width + aCaptionMargin.left;
01006     aOrigin.y = aInnerMargin.top;
01007     switch(GetCaptionVerticalAlign()) {
01008       case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
01009         aOrigin.y += PR_MAX(0, (aInnerSize.height - aCaptionSize.height) / 2);
01010         break;
01011       case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
01012         aOrigin.y += PR_MAX(0, aInnerSize.height - aCaptionSize.height);
01013         break;
01014       default:
01015         break;
01016     }
01017   } break;
01018   default: { // top
01019     if (NS_AUTOMARGIN == aCaptionMargin.left) {
01020       aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right,
01021                                            aContainBlockSize.width, aCaptionSize.width, p2t);
01022     }
01023     aOrigin.x = aCaptionMargin.left;
01024     if (NS_AUTOMARGIN == aCaptionMargin.bottom) {
01025       aCaptionMargin.bottom = 0;
01026     }
01027     if (NS_AUTOMARGIN == aCaptionMargin.top) {
01028       nsCollapsingMargin marg;
01029       marg.Include(aCaptionMargin.bottom);
01030       marg.Include(aInnerMargin.top);
01031       nscoord collapseMargin = marg.get();
01032       nscoord height = aCaptionSize.height + collapseMargin + aInnerSize.height;
01033       aCaptionMargin.top = CalcAutoMargin(aCaptionMargin.top, aInnerMargin.bottom,
01034                                           aContainBlockSize.height, height, p2t);
01035     }
01036     aOrigin.y = aCaptionMargin.top;
01037   } break;
01038   }
01039   return NS_OK;
01040 }
01041 
01042 nsresult 
01043 nsTableOuterFrame::GetInnerOrigin(nsPresContext*  aPresContext,
01044                                   PRUint32         aCaptionSide,
01045                                   const nsSize&    aContainBlockSize,
01046                                   const nsSize&    aCaptionSize, 
01047                                   const nsMargin&  aCaptionMargin,
01048                                   const nsSize&    aInnerSize,
01049                                   nsMargin&        aInnerMargin,
01050                                   nsPoint&         aOrigin)
01051 {
01052   aOrigin.x = aOrigin.y = 0;
01053   if ((NS_UNCONSTRAINEDSIZE == aInnerSize.width) || (NS_UNCONSTRAINEDSIZE == aInnerSize.height) ||  
01054       (NS_UNCONSTRAINEDSIZE == aCaptionSize.width) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.height)) {
01055     return NS_OK;
01056   }
01057 
01058   float p2t = aPresContext->ScaledPixelsToTwips();
01059 
01060   nscoord minCapWidth = aCaptionSize.width;
01061   if (NS_AUTOMARGIN != aCaptionMargin.left)
01062     minCapWidth += aCaptionMargin.left;
01063   if (NS_AUTOMARGIN != aCaptionMargin.right)
01064     minCapWidth += aCaptionMargin.right;
01065 
01066   switch(aCaptionSide) {
01067   case NS_SIDE_BOTTOM: {
01068     if (NS_AUTOMARGIN == aInnerMargin.left) {
01069       aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right,
01070                                          aContainBlockSize.width, aInnerSize.width, p2t);
01071     }
01072     aOrigin.x = aInnerMargin.left;
01073     if (NS_AUTOMARGIN == aInnerMargin.bottom) {
01074       aInnerMargin.bottom = 0;
01075     }
01076     if (NS_AUTOMARGIN == aInnerMargin.top) {
01077       nsCollapsingMargin marg;
01078       marg.Include(aInnerMargin.bottom);
01079       marg.Include(aCaptionMargin.top);
01080       nscoord collapseMargin = marg.get();
01081       nscoord height = aInnerSize.height + collapseMargin + aCaptionSize.height;
01082       aInnerMargin.top = CalcAutoMargin(aInnerMargin.top, aCaptionMargin.bottom,
01083                                         aContainBlockSize.height, height, p2t);
01084     }
01085     aOrigin.y = aInnerMargin.top;
01086   } break;
01087   case NS_SIDE_LEFT: {
01088     
01089     if (NS_AUTOMARGIN == aInnerMargin.left) {
01090       aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right,
01091                                          aContainBlockSize.width, aInnerSize.width, p2t);
01092       
01093     }
01094     if (aInnerMargin.left < minCapWidth) {
01095       // shift the inner table to get some place for the caption
01096       aInnerMargin.right += aInnerMargin.left - minCapWidth;
01097       aInnerMargin.right  = PR_MAX(0, aInnerMargin.right);
01098       aInnerMargin.left   = minCapWidth;
01099     }
01100     aOrigin.x = aInnerMargin.left;
01101     if (NS_AUTOMARGIN == aInnerMargin.top) {
01102       aInnerMargin.top = 0;
01103     }
01104     aOrigin.y = aInnerMargin.top;
01105     switch(GetCaptionVerticalAlign()) {
01106       case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
01107         aOrigin.y = PR_MAX(aInnerMargin.top, (aCaptionSize.height - aInnerSize.height) / 2);
01108         break;
01109       case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
01110         aOrigin.y = PR_MAX(aInnerMargin.top, aCaptionSize.height - aInnerSize.height);
01111         break;
01112       default:
01113         break;
01114     }
01115   } break;
01116   case NS_SIDE_RIGHT: {
01117     if (NS_AUTOMARGIN == aInnerMargin.right) {
01118       aInnerMargin.right = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right,
01119                                           aContainBlockSize.width, aInnerSize.width, p2t);
01120       if (aInnerMargin.right < minCapWidth) {
01121         // shift the inner table to get some place for the caption
01122         aInnerMargin.left -= aInnerMargin.right - minCapWidth;
01123         aInnerMargin.left  = PR_MAX(0, aInnerMargin.left);
01124         aInnerMargin.right = minCapWidth;
01125       }
01126     }
01127     aOrigin.x = aInnerMargin.left;
01128     if (NS_AUTOMARGIN == aInnerMargin.top) {
01129       aInnerMargin.top = 0;
01130     }
01131     aOrigin.y = aInnerMargin.top;
01132     switch(GetCaptionVerticalAlign()) {
01133       case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
01134         aOrigin.y = PR_MAX(aInnerMargin.top, (aCaptionSize.height - aInnerSize.height) / 2);
01135         break;
01136       case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
01137         aOrigin.y = PR_MAX(aInnerMargin.top, aCaptionSize.height - aInnerSize.height);
01138         break;
01139       default:
01140         break;
01141     }
01142   } break;
01143   default: { // top
01144     if (NS_AUTOMARGIN == aInnerMargin.left) {
01145       aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right,
01146                                          aContainBlockSize.width, aInnerSize.width, p2t);
01147     }
01148     aOrigin.x = aInnerMargin.left;
01149     if (NS_AUTOMARGIN == aInnerMargin.top) {
01150       aInnerMargin.top = 0;
01151     }
01152     nsCollapsingMargin marg;
01153     marg.Include(aCaptionMargin.bottom);
01154     marg.Include(aInnerMargin.top);
01155     nscoord collapseMargin = marg.get();
01156     if (NS_AUTOMARGIN == aInnerMargin.bottom) {
01157       nscoord height = aCaptionSize.height + collapseMargin + aInnerSize.height;
01158       aInnerMargin.bottom = CalcAutoMargin(aCaptionMargin.bottom, aInnerMargin.top,
01159                                            aContainBlockSize.height, height, p2t);
01160     }
01161     aOrigin.y = aCaptionMargin.top + aCaptionSize.height + collapseMargin;
01162   } break;
01163   }
01164   return NS_OK;
01165 }
01166 
01167 // helper method for determining if this is a nested table or not
01168 PRBool 
01169 nsTableOuterFrame::IsNested(const nsHTMLReflowState& aReflowState) const
01170 {
01171   // Walk up the reflow state chain until we find a cell or the root
01172   const nsHTMLReflowState* rs = aReflowState.parentReflowState;
01173   while (rs) {
01174     if (nsLayoutAtoms::tableFrame == rs->frame->GetType()) {
01175       return PR_TRUE;
01176     }
01177     rs = rs->parentReflowState;
01178   }
01179   return PR_FALSE;
01180 }
01181 
01182 PRBool 
01183 nsTableOuterFrame::IsAutoWidth(nsIFrame& aTableOrCaption,
01184                                PRBool*   aIsPctWidth)
01185 {
01186   PRBool isAuto = PR_TRUE;  // the default
01187   if (aIsPctWidth) {
01188     *aIsPctWidth = PR_FALSE;
01189   }
01190 
01191   const nsStylePosition* position = aTableOrCaption.GetStylePosition();
01192 
01193 #ifdef __SUNPRO_CC
01194   // Bug 239962, this is a workaround to avoid incorrect code generation by Sun Forte compiler.
01195   float percent = position->mWidth.GetPercentValue();
01196 #endif
01197 
01198   switch (position->mWidth.GetUnit()) {
01199     case eStyleUnit_Auto:         // specified auto width
01200     case eStyleUnit_Proportional: // illegal for table, so ignored
01201       break;
01202     case eStyleUnit_Coord:
01203       isAuto = PR_FALSE;
01204       break;
01205     case eStyleUnit_Percent:
01206 #ifdef __SUNPRO_CC
01207       if (percent > 0.0f) {
01208 #else
01209       if (position->mWidth.GetPercentValue() > 0.0f) {
01210 #endif
01211         isAuto = PR_FALSE;
01212         if (aIsPctWidth) {
01213           *aIsPctWidth = PR_TRUE;
01214         }
01215       }
01216       break;
01217     default:
01218       break;
01219   }
01220 
01221   return isAuto; 
01222 }
01223 // eReflowReason_Resize was being used for incremental cases
01224 
01225 nsresult
01226 nsTableOuterFrame::OuterReflowChild(nsPresContext*            aPresContext,
01227                                     nsIFrame*                  aChildFrame,
01228                                     const nsHTMLReflowState&   aOuterRS,
01229                                     nsHTMLReflowMetrics&       aMetrics,
01230                                     nscoord                    aAvailWidth, 
01231                                     nsSize&                    aDesiredSize,
01232                                     nsMargin&                  aMargin,
01233                                     nsMargin&                  aMarginNoAuto,
01234                                     nsMargin&                  aPadding,
01235                                     nsReflowReason             aReflowReason,
01236                                     nsReflowStatus&            aStatus,
01237                                     PRBool*                    aNeedToReflowCaption)
01238 { 
01239   aMargin = aPadding = nsMargin(0,0,0,0);
01240 
01241   // work around pixel rounding errors, round down to ensure we don't exceed the avail height in
01242   nscoord availHeight = aOuterRS.availableHeight;
01243   if (NS_UNCONSTRAINEDSIZE != availHeight) {
01244     nsMargin margin, marginNoAuto, padding;
01245     GetMarginPadding(aPresContext, aOuterRS, aChildFrame, aOuterRS.availableWidth, margin, 
01246                      marginNoAuto, padding);
01247     
01248     NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.top, "No unconstrainedsize arithmetic, please");
01249     availHeight -= margin.top;
01250     
01251     NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.bottom, "No unconstrainedsize arithmetic, please");
01252     availHeight -= margin.bottom;
01253     
01254     availHeight = nsTableFrame::RoundToPixel(availHeight,
01255                                            aPresContext->ScaledPixelsToTwips(),
01256                                              eAlwaysRoundDown);
01257   }
01258   nsSize availSize(aAvailWidth, availHeight);
01259   if (mCaptionFrame == aChildFrame) {
01260     PRUint8 captionSide = GetCaptionSide();
01261     if ((NS_SIDE_LEFT  == captionSide) || (NS_SIDE_RIGHT != captionSide)) {
01262       PRBool isPctWidth;
01263       IsAutoWidth(*aChildFrame, &isPctWidth);
01264       if (isPctWidth) {
01265         availSize.width = aOuterRS.availableWidth;
01266       }
01267     }
01268   }
01269   // create and init the child reflow state
01270   nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, availSize, 
01271                             aReflowReason);
01272   InitChildReflowState(*aPresContext, childRS);
01273   childRS.mPercentHeightObserver = nsnull; // the observer is for non table related frames inside cells
01274 
01275 
01276   // If mComputedWidth > availWidth and availWidth >= minWidth for a nested percent table 
01277   // then adjust mComputedWidth based on availableWidth if this isn't the intial reflow   
01278   if ((NS_UNCONSTRAINEDSIZE != childRS.mComputedWidth)  &&
01279       (eReflowReason_Initial != aReflowReason)          &&
01280       (childRS.mComputedWidth + childRS.mComputedBorderPadding.left +
01281        childRS.mComputedBorderPadding.right > childRS.availableWidth) &&
01282       IsNested(aOuterRS)) {
01283     PRBool isPctWidth;
01284     IsAutoWidth(*aChildFrame, &isPctWidth);
01285     if (isPctWidth) {
01286       if ( ((aChildFrame == mInnerTableFrame) && 
01287             ((nsTableFrame*)aChildFrame)->GetMinWidth() <= childRS.availableWidth) ||
01288            (aChildFrame != mInnerTableFrame)) {
01289         childRS.mComputedWidth = childRS.availableWidth - childRS.mComputedBorderPadding.left -
01290                                                           childRS.mComputedBorderPadding.right;
01291       }
01292     }
01293   }
01294 
01295   // see if we need to reset top of page due to a caption
01296   if (mCaptionFrame) {
01297     PRUint8 captionSide = GetCaptionSide();
01298     if (((NS_SIDE_BOTTOM == captionSide) && (mCaptionFrame == aChildFrame)) || 
01299         ((NS_SIDE_TOP == captionSide) && (mInnerTableFrame == aChildFrame))) {
01300       childRS.mFlags.mIsTopOfPage = PR_FALSE;
01301     }
01302     if ((mCaptionFrame == aChildFrame) && (NS_SIDE_LEFT  != captionSide) 
01303                                        && (NS_SIDE_RIGHT != captionSide)) {
01304       aAvailWidth = aOuterRS.availableWidth;
01305     }
01306   }
01307   // see if we need to reflow the caption in addition
01308   if (aNeedToReflowCaption && !*aNeedToReflowCaption &&
01309       mInnerTableFrame == aChildFrame && childRS.reason == eReflowReason_Incremental) {
01310     nsHTMLReflowCommand* command = childRS.path->mReflowCommand;
01311     if (command) {
01312       *aNeedToReflowCaption = eReflowType_StyleChanged == command->Type();
01313     }
01314   }
01315 
01316   // use the current position as a best guess for placement
01317   nsPoint childPt = aChildFrame->GetPosition();
01318   nsresult rv = ReflowChild(aChildFrame, aPresContext, aMetrics, childRS,
01319                             childPt.x, childPt.y, NS_FRAME_NO_MOVE_FRAME, aStatus);
01320   if (NS_FAILED(rv)) return rv;
01321   
01322   FixAutoMargins(aAvailWidth, aMetrics.width, childRS);
01323   aMargin = childRS.mComputedMargin;
01324   aMarginNoAuto = childRS.mComputedMargin;
01325   ZeroAutoMargin(childRS, aMarginNoAuto);
01326 
01327   aDesiredSize.width  = aMetrics.width;
01328   aDesiredSize.height = aMetrics.height;
01329 
01330   return rv;
01331 }
01332 
01333 void 
01334 nsTableOuterFrame::UpdateReflowMetrics(PRUint8              aCaptionSide,
01335                                        nsHTMLReflowMetrics& aMet,
01336                                        const nsMargin&      aInnerMargin,
01337                                        const nsMargin&      aInnerMarginNoAuto,
01338                                        const nsMargin&      aInnerPadding,
01339                                        const nsMargin&      aCaptionMargin,
01340                                        const nsMargin&      aCaptionMarginNoAuto,
01341                                        const nscoord        aAvailableWidth)
01342 {
01343   SetDesiredSize(aCaptionSide, aInnerMargin, aCaptionMargin, aAvailableWidth, aMet.width, aMet.height);
01344 
01345   // set maxElementSize width if requested
01346   if (aMet.mComputeMEW) {
01347     aMet.mMaxElementWidth = GetMaxElementWidth(aCaptionSide, aInnerMarginNoAuto, aInnerPadding, aCaptionMarginNoAuto);
01348   }
01349   // set maximum width if requested
01350   if (aMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
01351     aMet.mMaximumWidth = GetMaxWidth(aCaptionSide, aInnerMarginNoAuto, aCaptionMarginNoAuto);
01352   }
01353  
01354   aMet.mOverflowArea = nsRect(0, 0, aMet.width, aMet.height);
01355   ConsiderChildOverflow(aMet.mOverflowArea, mInnerTableFrame);
01356   if (mCaptionFrame) {
01357     ConsiderChildOverflow(aMet.mOverflowArea, mCaptionFrame);
01358   }
01359   FinishAndStoreOverflow(&aMet);
01360 }
01361 
01362 nsresult 
01363 nsTableOuterFrame::IncrementalReflow(nsPresContext*          aPresContext,
01364                                      nsHTMLReflowMetrics&     aDesiredSize,
01365                                      const nsHTMLReflowState& aReflowState,
01366                                      nsReflowStatus&          aStatus)
01367 {
01368   // the outer table is a target if its path has a reflow command
01369   nsHTMLReflowCommand* command = aReflowState.path->mReflowCommand;
01370   if (command)
01371     IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus);
01372 
01373   // see if the chidren are targets as well
01374   nsReflowPath::iterator iter = aReflowState.path->FirstChild();
01375   nsReflowPath::iterator end  = aReflowState.path->EndChildren();
01376   for (; iter != end; ++iter)
01377     IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, *iter);
01378 
01379   return NS_OK;
01380 }
01381 
01382 nsresult 
01383 nsTableOuterFrame::IR_TargetIsChild(nsPresContext*          aPresContext,
01384                                     nsHTMLReflowMetrics&     aDesiredSize,
01385                                     const nsHTMLReflowState& aReflowState,
01386                                     nsReflowStatus&          aStatus,
01387                                     nsIFrame*                aNextFrame)
01388 {
01389   nsresult rv;
01390   if (!aNextFrame) {
01391     // this will force Reflow to return the height of the last reflow rather than 0
01392     aDesiredSize.height = mRect.height; 
01393     return NS_OK;
01394   }
01395 
01396   if (aNextFrame == mInnerTableFrame) {
01397     rv = IR_TargetIsInnerTableFrame(aPresContext, aDesiredSize, aReflowState, aStatus);
01398   }
01399   else if (aNextFrame == mCaptionFrame) {
01400     rv = IR_TargetIsCaptionFrame(aPresContext, aDesiredSize, aReflowState, aStatus);
01401   }
01402   else {
01403     const nsStyleDisplay* nextDisplay = aNextFrame->GetStyleDisplay();
01404     if (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP==nextDisplay->mDisplay ||
01405         NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP==nextDisplay->mDisplay ||
01406         NS_STYLE_DISPLAY_TABLE_ROW_GROUP   ==nextDisplay->mDisplay ||
01407         NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP==nextDisplay->mDisplay) {
01408       rv = IR_TargetIsInnerTableFrame(aPresContext, aDesiredSize, aReflowState, aStatus);
01409     }
01410     else {
01411       NS_ASSERTION(PR_FALSE, "illegal next frame in incremental reflow.");
01412       rv = NS_ERROR_ILLEGAL_VALUE;
01413     }
01414   }
01415   return rv;
01416 }
01417 
01418 nsresult 
01419 nsTableOuterFrame::IR_TargetIsInnerTableFrame(nsPresContext*           aPresContext,
01420                                               nsHTMLReflowMetrics&      aDesiredSize,
01421                                               const nsHTMLReflowState&  aReflowState,
01422                                               nsReflowStatus&           aStatus)
01423 {
01424   nsresult rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
01425   return rv;
01426 }
01427 
01428 nsresult 
01429 nsTableOuterFrame::IR_TargetIsCaptionFrame(nsPresContext*           aPresContext,
01430                                            nsHTMLReflowMetrics&      aDesiredSize,
01431                                            const nsHTMLReflowState&  aOuterRS,
01432                                            nsReflowStatus&           aStatus)
01433 {
01434   nsresult rv = NS_OK;
01435   aStatus = NS_FRAME_COMPLETE;
01436   PRUint8 captionSide = GetCaptionSide();
01437 
01438   nsSize captionSize;
01439   nsMargin captionMargin, captionMarginNoAuto, captionPadding;
01440   // reflow the caption frame, getting it's MES
01441   nsRect prevInnerRect = mInnerTableFrame->GetRect();
01442   nsMargin prevInnerMargin(prevInnerRect.x, 0, mRect.width - prevInnerRect.x - prevInnerRect.width, 0);
01443   nscoord availCaptionWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, captionMargin, 
01444                                                    captionPadding, &prevInnerRect.width, nsnull, &prevInnerMargin);
01445   nsHTMLReflowMetrics captionMet(PR_TRUE);
01446   nsReflowStatus capStatus; // don't let the caption cause incomplete
01447   // for now just reflow the table if a style changed. This should be improved
01448   PRBool needInnerReflow = PR_FALSE;
01449   nsReflowReason reflowReason = eReflowReason_Incremental;
01450   nsHTMLReflowCommand* command = aOuterRS.path->mReflowCommand;
01451   if (command) {
01452     switch(command->Type()) {
01453       case eReflowType_StyleChanged:
01454         needInnerReflow = PR_TRUE;
01455         break;
01456       default:
01457         break;
01458     }
01459   }
01460   
01461   OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, availCaptionWidth, captionSize, 
01462                    captionMargin, captionMarginNoAuto, captionPadding, reflowReason, capStatus);
01463 
01464   nsMargin innerMargin, innerMarginNoAuto, innerPadding;
01465   nsPoint  innerOrigin;
01466   nsSize   containSize = GetContainingBlockSize(aOuterRS);
01467   nscoord  capMin = mMinCaptionWidth + captionMarginNoAuto.left + captionMarginNoAuto.right;
01468   
01469 
01470   if (mMinCaptionWidth != captionMet.mMaxElementWidth) {  
01471     // set the new caption min width, and set state to reflow the inner table if necessary
01472     mMinCaptionWidth = captionMet.mMaxElementWidth;
01473     // see if the captions min width could cause the table to be wider
01474     // XXX this really only affects an auto width table
01475     if ((capMin) > mRect.width) {
01476       needInnerReflow = PR_TRUE;
01477     }
01478   }
01479   if (NS_SIDE_LEFT == captionSide || NS_SIDE_RIGHT == captionSide) {
01480     if (mCaptionFrame) {
01481       PRBool isPctWidth;
01482       IsAutoWidth( *mCaptionFrame,&isPctWidth);
01483       if (isPctWidth) {
01484         capMin = captionSize.width + captionMarginNoAuto.left + captionMarginNoAuto.right;
01485       }
01486     }
01487   }
01488 
01489   nsPoint captionOrigin;
01490   if (needInnerReflow) {
01491     nsSize innerSize;
01492     nsHTMLReflowMetrics innerMet(PR_FALSE);
01493     nscoord availTableWidth = GetInnerTableAvailWidth(aPresContext, mInnerTableFrame, aOuterRS, 
01494                                                       &capMin, innerMargin, innerPadding);
01495     OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, availTableWidth, innerSize, 
01496                      innerMargin, innerMarginNoAuto, innerPadding, eReflowReason_Resize, aStatus);
01497 
01498     GetInnerOrigin(aPresContext, captionSide, containSize, captionSize,
01499                    captionMargin, innerSize, innerMargin, innerOrigin);
01500     rv = FinishReflowChild(mInnerTableFrame, aPresContext, nsnull, innerMet,
01501                            innerOrigin.x, innerOrigin.y, 0);
01502     if (NS_FAILED(rv)) return rv;
01503     
01504     GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01505                      innerMargin, captionSize, captionMargin, captionOrigin);
01506   }
01507   else {
01508     // reposition the inner frame if necessary and set the caption's origin
01509     nsSize innerSize = mInnerTableFrame->GetSize();
01510     GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, aOuterRS.availableWidth, innerMargin, 
01511                      innerMarginNoAuto, innerPadding);
01512     GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01513                    captionMargin, innerSize, innerMargin, innerOrigin);
01514     GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01515                      innerMargin, captionSize, captionMargin, captionOrigin);
01516     MoveFrameTo(mInnerTableFrame, innerOrigin.x, innerOrigin.y); 
01517   }
01518 
01519   rv = FinishReflowChild(mCaptionFrame, aPresContext, nsnull, captionMet,
01520                          captionOrigin.x, captionOrigin.y, 0);
01521   nsRect* oldOverflowArea = GetOverflowAreaProperty();
01522   nsRect* overflowStorage = nsnull;
01523   nsRect  overflow;
01524   if (oldOverflowArea) {
01525     overflow = *oldOverflowArea;
01526     overflowStorage = &overflow;
01527   }
01528 
01529   UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, 
01530                       innerPadding, captionMargin, captionMarginNoAuto, aOuterRS.availableWidth);
01531   nsSize desSize(aDesiredSize.width, aDesiredSize.height);
01532   PRBool innerMoved = (innerOrigin.x != prevInnerRect.x) || (innerOrigin.y != prevInnerRect.y);
01533   InvalidateDamage(captionSide, desSize, innerMoved, PR_TRUE, overflowStorage);
01534   return rv;
01535 }
01536 
01537 nsresult
01538 nsTableOuterFrame::IR_ReflowDirty(nsPresContext*           aPresContext,
01539                                   nsHTMLReflowMetrics&      aDesiredSize,
01540                                   const nsHTMLReflowState&  aReflowState,
01541                                   nsReflowStatus&           aStatus)
01542 {
01543   nsresult      rv = NS_OK;
01544   PRBool sizeSet = PR_FALSE;
01545   // See if the caption frame is dirty. This would be because of a newly
01546   // inserted caption
01547   if (mCaptionFrame) {
01548     if (mCaptionFrame->GetStateBits() & NS_FRAME_IS_DIRTY) {
01549       rv = IR_CaptionInserted(aPresContext, aDesiredSize, aReflowState, aStatus);
01550       sizeSet = PR_TRUE;
01551     }
01552   }
01553 
01554   // See if the inner table frame is dirty
01555   if (mInnerTableFrame->GetStateBits() & NS_FRAME_IS_DIRTY) {
01556     rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
01557     sizeSet = PR_TRUE;
01558   } 
01559   else if (!mCaptionFrame) {
01560     // The inner table isn't dirty so we don't need to reflow it, but make
01561     // sure it's placed correctly. It could be that we're dirty because the
01562     // caption was removed
01563     nsRect   innerRect = mInnerTableFrame->GetRect();
01564     nsSize   innerSize(innerRect.width, innerRect.height);
01565     nsPoint  innerOrigin;
01566     nsMargin innerMargin, innerMarginNoAuto, innerPadding;
01567     GetMarginPadding(aPresContext, aReflowState, mInnerTableFrame, aReflowState.availableWidth, innerMargin, 
01568                      innerMarginNoAuto, innerPadding);
01569     nsSize containSize = GetContainingBlockSize(aReflowState);
01570     GetInnerOrigin(aPresContext, NO_SIDE, containSize, nsSize(0,0),
01571                    nsMargin(0,0,0,0), innerSize, innerMargin, innerOrigin);
01572     MoveFrameTo(mInnerTableFrame, innerOrigin.x, innerOrigin.y); 
01573 
01574     aDesiredSize.width  = innerRect.XMost() + innerMargin.right;
01575     aDesiredSize.height = innerRect.YMost() + innerMargin.bottom; 
01576     sizeSet = PR_TRUE;
01577     // Repaint the inner's entire bounds if it moved
01578     nsRect* oldOverflowArea = GetOverflowAreaProperty();
01579     PRBool innerMoved = (innerRect.x != innerOrigin.x) ||
01580                          (innerRect.y != innerOrigin.y);
01581     nsSize desSize(aDesiredSize.width, aDesiredSize.height);
01582     InvalidateDamage((PRUint8) NO_SIDE, desSize, innerMoved, PR_FALSE, oldOverflowArea);
01583   }
01584   if (!sizeSet) {
01585     // set our desired size to what it was before
01586     nsSize size = GetSize();
01587     aDesiredSize.width  = size.width;
01588     aDesiredSize.height = size.height;
01589   }
01590 
01591   return rv;
01592 }
01593 
01594 // IR_TargetIsMe is free to foward the request to the inner table frame 
01595 nsresult nsTableOuterFrame::IR_TargetIsMe(nsPresContext*           aPresContext,
01596                                           nsHTMLReflowMetrics&      aDesiredSize,
01597                                           const nsHTMLReflowState&  aReflowState,
01598                                           nsReflowStatus&           aStatus)
01599 {
01600   nsresult rv = NS_OK;
01601   switch (aReflowState.path->mReflowCommand->Type()) {
01602   case eReflowType_ReflowDirty:
01603      rv = IR_ReflowDirty(aPresContext, aDesiredSize, aReflowState, aStatus);
01604     break;
01605 
01606   case eReflowType_StyleChanged :    
01607     rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
01608     break;
01609 
01610   case eReflowType_ContentChanged :
01611     NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged");
01612     rv = NS_ERROR_ILLEGAL_VALUE;
01613     break;
01614   
01615   default:
01616     NS_NOTYETIMPLEMENTED("unexpected reflow command type");
01617     rv = NS_ERROR_NOT_IMPLEMENTED;
01618     break;
01619   }
01620 
01621   return rv;
01622 }
01623 
01624 nsresult 
01625 nsTableOuterFrame::IR_InnerTableReflow(nsPresContext*           aPresContext,
01626                                        nsHTMLReflowMetrics&      aOuterMet,
01627                                        const nsHTMLReflowState&  aOuterRS,
01628                                        nsReflowStatus&           aStatus)
01629 {
01630   aStatus = NS_FRAME_COMPLETE;
01631   PRUint8 captionSide = GetCaptionSide();
01632 
01633   nsSize priorInnerSize = mInnerTableFrame->GetSize();
01634 
01635   nsSize   innerSize;
01636   nsMargin innerMargin, innerMarginNoAuto, innerPadding;
01637 
01638   // pass along the reflow command to the inner table, requesting the same info in our flags
01639   nsHTMLReflowMetrics innerMet(aOuterMet.mComputeMEW, aOuterMet.mFlags);
01640 
01641   // If the incremental reflow command is a StyleChanged reflow and
01642   // it's target is the current frame, then make sure we send
01643   // StyleChange reflow reasons down to the children so that they
01644   // don't over-optimize their reflow.  Also make sure we reflow the caption.
01645   PRBool reflowCaption = PR_FALSE;
01646   nsReflowReason reflowReason = eReflowReason_Incremental;
01647   nsHTMLReflowCommand* command = aOuterRS.path->mReflowCommand;
01648   if (command) {
01649     if (eReflowType_StyleChanged == command->Type()) {
01650       reflowReason = eReflowReason_StyleChange;
01651       reflowCaption = PR_TRUE;
01652     }
01653   }
01654   nscoord capMin = mMinCaptionWidth;
01655   PctAdjustMinCaptionWidth(aPresContext, aOuterRS, captionSide, capMin);
01656   nscoord availTableWidth = GetInnerTableAvailWidth(aPresContext, mInnerTableFrame, aOuterRS, 
01657                                                     &capMin, innerMargin, innerPadding);
01658   nsresult rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet,
01659                                  availTableWidth, innerSize, innerMargin, innerMarginNoAuto,
01660                                  innerPadding, reflowReason, aStatus, &reflowCaption);
01661   if (NS_FAILED(rv)) return rv;
01662   
01663   if (eReflowReason_StyleChange != reflowReason && reflowCaption) {
01664     // inner table frame was target for a style change reflow issue a style 
01665     // change reflow for the caption too.
01666     reflowReason = eReflowReason_StyleChange;
01667   }
01668   nsPoint  innerOrigin(0,0);
01669   nsMargin captionMargin(0,0,0,0);
01670   nsMargin captionMarginNoAuto(0,0,0,0);
01671   nsSize   captionSize(0,0);
01672   nsSize   containSize = GetContainingBlockSize(aOuterRS);
01673   PRBool   captionMoved = PR_FALSE;
01674   // if there is a caption and the width or height of the inner table changed 
01675   // from a reflow, then reflow or move the caption as needed
01676   if (mCaptionFrame) {
01677     nsPoint captionOrigin;
01678     nsRect prevCaptionRect = mCaptionFrame->GetRect();
01679 
01680     reflowCaption = reflowCaption ||
01681                     priorInnerSize.width != innerMet.width;
01682 
01683     if (reflowCaption) {
01684       nsMargin ignorePadding;
01685       nsHTMLReflowMetrics captionMet(eReflowReason_StyleChange == reflowReason);
01686       nscoord availCaptionWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, captionMargin,
01687                                                        ignorePadding, &innerSize.width, &innerMarginNoAuto);
01688       nsReflowStatus capStatus; // don't let the caption cause incomplete
01689       if (reflowReason == eReflowReason_Incremental) {
01690          reflowReason = eReflowReason_Resize;
01691       }
01692       rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, availCaptionWidth,
01693                             captionSize, captionMargin, captionMarginNoAuto, 
01694                             ignorePadding, reflowReason, capStatus);
01695       if (NS_FAILED(rv)) return rv;
01696 
01697       GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01698                        innerMargin, captionSize, captionMargin, captionOrigin);
01699       FinishReflowChild(mCaptionFrame, aPresContext, nsnull, captionMet,
01700                         captionOrigin.x, captionOrigin.y, 0);
01701 
01702       GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01703                      captionMargin, innerSize, innerMargin, innerOrigin);
01704     }
01705     else {
01706       // reposition the caption frame if necessary and set the inner's origin
01707       captionSize = mCaptionFrame->GetSize();
01708       nsMargin captionPadding;
01709       GetMarginPadding(aPresContext, aOuterRS, mCaptionFrame, aOuterRS.availableWidth, captionMargin, 
01710                        captionMarginNoAuto, captionPadding);
01711       GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01712                        innerMargin, captionSize, captionMargin, captionOrigin);
01713       GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01714                      captionMargin, innerSize, innerMargin, innerOrigin);
01715       MoveFrameTo(mCaptionFrame, captionOrigin.x, captionOrigin.y); 
01716     }
01717     if ((captionOrigin.x != prevCaptionRect.x) || (captionOrigin.y != prevCaptionRect.y)) {
01718       captionMoved = PR_TRUE;
01719     }
01720     if ((captionSize.width != prevCaptionRect.width) || (captionSize.height != prevCaptionRect.height)) {
01721       captionMoved = PR_TRUE;
01722     }
01723   }
01724   else {
01725     GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01726                    captionMargin, innerSize, innerMargin, innerOrigin);
01727   }
01728 
01729   FinishReflowChild(mInnerTableFrame, aPresContext, nsnull, innerMet,
01730                     innerOrigin.x, innerOrigin.y, 0);
01731   if (aOuterMet.mComputeMEW) {
01732     aOuterMet.mMaxElementWidth = innerMet.mMaxElementWidth;
01733   }
01734   nsRect* oldOverflowArea = GetOverflowAreaProperty();
01735   nsRect* overflowStorage = nsnull;
01736   nsRect  overflow;
01737   if (oldOverflowArea) {
01738     overflow = *oldOverflowArea;
01739     overflowStorage = &overflow;
01740   }
01741   
01742   UpdateReflowMetrics(captionSide, aOuterMet, innerMargin, innerMarginNoAuto, 
01743                       innerPadding, captionMargin, captionMarginNoAuto, aOuterRS.availableWidth);
01744   nsSize desSize(aOuterMet.width, aOuterMet.height);
01745   InvalidateDamage(captionSide, desSize, (innerSize.width != priorInnerSize.width),
01746                    captionMoved, overflowStorage);
01747 
01748   return rv;
01749 }
01750 
01751 /* the only difference between an insert and a replace is a replace 
01752    checks the old maxElementWidth and reflows the table only if it
01753    has changed
01754 */
01755 nsresult 
01756 nsTableOuterFrame::IR_CaptionInserted(nsPresContext*           aPresContext,
01757                                       nsHTMLReflowMetrics&      aDesiredSize,
01758                                       const nsHTMLReflowState&  aOuterRS,
01759                                       nsReflowStatus&           aStatus)
01760 {
01761   PRUint8 captionSide = GetCaptionSide();
01762   aStatus = NS_FRAME_COMPLETE;
01763 
01764   // reflow the caption frame, getting it's MES
01765   nsSize   captionSize;
01766   nsMargin captionMargin, captionMarginNoAuto, captionPadding;
01767   nsHTMLReflowMetrics captionMet(PR_TRUE);
01768   // reflow the caption
01769   nscoord availCaptionWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, captionMargin, captionPadding);
01770   nsReflowStatus capStatus; // don't let the caption cause incomplete
01771   nsresult rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet,
01772                                  availCaptionWidth, captionSize, captionMargin, captionMarginNoAuto,
01773                                  captionPadding, eReflowReason_Initial, capStatus);
01774 
01775   if (NS_FAILED(rv)) return rv;
01776 
01777   mMinCaptionWidth = captionMet.mMaxElementWidth;
01778 
01779   nsPoint  captionOrigin(0,0); 
01780 
01781   nsMargin innerMargin, innerMarginNoAuto, innerPadding;
01782   nsPoint innerOrigin;
01783   nsSize containSize = GetContainingBlockSize(aOuterRS);
01784   nsPoint prevInnerOrigin = mInnerTableFrame->GetPosition();
01785   nscoord capMin = mMinCaptionWidth + captionMarginNoAuto.left + captionMarginNoAuto.right;
01786 
01787   // if the caption's MES + margins > outer width, reflow the inner table
01788   if (capMin > mRect.width) {
01789     nsHTMLReflowMetrics innerMet(aDesiredSize.mComputeMEW); 
01790     nsSize innerSize;
01791     nscoord availTableWidth = GetInnerTableAvailWidth(aPresContext, mInnerTableFrame, aOuterRS, 
01792                                                       &capMin, innerMargin, innerPadding);
01793     rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet,
01794                           availTableWidth, innerSize, innerMargin, innerMarginNoAuto,
01795                           innerPadding, eReflowReason_Resize, aStatus);
01796     if (NS_FAILED(rv)) return rv;
01797 
01798     GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01799                    captionMargin, innerSize, innerMargin, innerOrigin);
01800     rv = FinishReflowChild(mInnerTableFrame, aPresContext, nsnull, innerMet,
01801                            innerOrigin.x, innerOrigin.y, 0);
01802     if (aDesiredSize.mComputeMEW) {
01803       aDesiredSize.mMaxElementWidth = innerMet.mMaxElementWidth;
01804     }
01805     if (NS_FAILED(rv)) return rv;
01806     GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01807                      innerMargin, captionSize, captionMargin, captionOrigin);
01808   }
01809   else {
01810     // reposition the inner frame if necessary and set the caption's origin
01811     nsSize innerSize = mInnerTableFrame->GetSize();
01812     GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, aOuterRS.availableWidth, innerMargin, 
01813                      innerMarginNoAuto, innerPadding);
01814     GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01815                    captionMargin, innerSize, innerMargin, innerOrigin);
01816     GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01817                      innerMargin, captionSize, captionMargin, captionOrigin);
01818     MoveFrameTo(mInnerTableFrame, innerOrigin.x, innerOrigin.y); 
01819   }
01820 
01821   rv = FinishReflowChild(mCaptionFrame, aPresContext, nsnull, captionMet,
01822                          captionOrigin.x, captionOrigin.y, 0);
01823 
01824   nsRect* oldOverflowArea = GetOverflowAreaProperty();
01825   nsRect* overflowStorage = nsnull;
01826   nsRect  overflow;
01827   if (oldOverflowArea) {
01828     overflow = *oldOverflowArea;
01829     overflowStorage = &overflow;
01830   }
01831   UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, 
01832                       innerPadding, captionMargin, captionMarginNoAuto, aOuterRS.availableWidth);
01833   nsSize desSize(aDesiredSize.width, aDesiredSize.height);
01834   PRBool innerMoved = innerOrigin != prevInnerOrigin;
01835   InvalidateDamage(captionSide, desSize, innerMoved, PR_TRUE, overflowStorage);
01836 
01837   return rv;
01838 }
01839 
01840 PRBool nsTableOuterFrame::IR_CaptionChangedAxis(const nsStyleTable* aOldStyle, 
01841                                                 const nsStyleTable* aNewStyle) const
01842 {
01843   PRBool result = PR_FALSE;
01844   //XXX: write me to support left|right captions!
01845   return result;
01846 }
01847 
01848 
01849 static PRBool
01850 IsPctHeight(nsIFrame* aFrame)
01851 {
01852   if (aFrame) {
01853     const nsStylePosition* position = aFrame->GetStylePosition();
01854     if (eStyleUnit_Percent == position->mHeight.GetUnit()) {
01855       float percent = position->mHeight.GetPercentValue();
01856       if (percent > 0.0f) {
01857         return PR_TRUE;
01858       }
01859     }
01860   }
01861   return PR_FALSE;
01862 }
01863 
01879 NS_METHOD nsTableOuterFrame::Reflow(nsPresContext*          aPresContext,
01880                                     nsHTMLReflowMetrics&     aDesiredSize,
01881                                     const nsHTMLReflowState& aOuterRS,
01882                                     nsReflowStatus&          aStatus)
01883 {
01884   DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame", aOuterRS.reason);
01885   DISPLAY_REFLOW(aPresContext, this, aOuterRS, aDesiredSize, aStatus);
01886 #if defined DEBUG_TABLE_REFLOW_TIMING
01887   nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS);
01888 #endif
01889 
01890   // We desperately need an inner table frame, 
01891   // if this fails fix the frame constructor
01892   if (mFrames.IsEmpty() || !mInnerTableFrame) {
01893     NS_ERROR("incomplete children");
01894     return NS_ERROR_FAILURE;
01895   }
01896   nsresult rv = NS_OK;
01897   PRUint8 captionSide = GetCaptionSide();
01898 
01899   // Initialize out parameters
01900   aDesiredSize.width = aDesiredSize.height = 0;
01901   if (aDesiredSize.mComputeMEW) {
01902     aDesiredSize.mMaxElementWidth =  0;
01903   }
01904   aStatus = NS_FRAME_COMPLETE;
01905 
01906   PRBool needUpdateMetrics = PR_TRUE;
01907   PRBool isPctWidth;
01908   IsAutoWidth(*mInnerTableFrame, &isPctWidth);
01909   if ((eReflowReason_Resize    == aOuterRS.reason)  &&
01910       (aOuterRS.availableWidth == mPriorAvailWidth) &&
01911       !aPresContext->IsPaginated()                  &&
01912       !::IsPctHeight(mInnerTableFrame)              &&
01913       !isPctWidth) {
01914     // don't do much if we are resize reflowed exactly like last time
01915     aDesiredSize.width  = mRect.width;
01916     aDesiredSize.height = mRect.height;
01917 
01918     // for floats, our view has not been positioned yet as we have not been placed
01919     //  - the block code will position our views after the float is placed
01920     if (aOuterRS.mStyleDisplay &&
01921         !aOuterRS.mStyleDisplay->IsFloating()) {
01922       // We know our view (if we have one) has been positioned
01923       // correctly, but it's up to us to make sure that our child views
01924       // are correctly positioned, too.
01925       nsContainerFrame::PositionChildViews(this);
01926     }
01927   }
01928   else if (eReflowReason_Incremental == aOuterRS.reason) {
01929     rv = IncrementalReflow(aPresContext, aDesiredSize, aOuterRS, aStatus);
01930   } 
01931   else {
01932     if (eReflowReason_Initial == aOuterRS.reason) {
01933       // Set up our kids.  They're already present, on an overflow list, 
01934       // or there are none so we'll create them now
01935       MoveOverflowToChildList(aPresContext);
01936 
01937       // Lay out the caption and get its maximum element size
01938       if (nsnull != mCaptionFrame) {
01939         nsHTMLReflowMetrics captionMet(PR_TRUE);
01940         nsHTMLReflowState captionReflowState(aPresContext, aOuterRS, mCaptionFrame,
01941                                              nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
01942                                              eReflowReason_Initial);
01943 
01944         mCaptionFrame->WillReflow(aPresContext);
01945         rv = mCaptionFrame->Reflow(aPresContext, captionMet, captionReflowState, aStatus);
01946         mCaptionFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
01947         mMinCaptionWidth = captionMet.mMaxElementWidth;
01948       }
01949     }
01950 
01951     nsSize   innerSize;
01952     nsMargin innerMargin, innerMarginNoAuto, innerPadding;
01953 
01954     // First reflow the inner table
01955     nsHTMLReflowMetrics innerMet(aDesiredSize.mComputeMEW);
01956     
01957     nscoord capMin = mMinCaptionWidth;
01958     PctAdjustMinCaptionWidth(aPresContext, aOuterRS, captionSide, capMin);
01959 
01960     nscoord availTableWidth = GetInnerTableAvailWidth(aPresContext, mInnerTableFrame, aOuterRS, 
01961                                                  &capMin, innerMargin, innerPadding);
01962     rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet,
01963                           availTableWidth, innerSize, innerMargin, innerMarginNoAuto,
01964                           innerPadding, aOuterRS.reason, aStatus);
01965     if (NS_FAILED(rv)) return rv;
01966 
01967     nsPoint  innerOrigin(0,0);
01968     nsMargin captionMargin(0,0,0,0), captionMarginNoAuto(0,0,0,0), ignorePadding;
01969     nsSize   captionSize(0,0);
01970     nsSize   containSize = GetContainingBlockSize(aOuterRS);
01971 
01972     // Now that we know the table width we can reflow the caption, and
01973     // place the caption and the inner table
01974     if (mCaptionFrame) {
01975       // reflow the caption
01976       nscoord availCaptionWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, captionMargin,
01977                                                        ignorePadding, &innerSize.width, &innerMarginNoAuto, &innerMargin);
01978       nsHTMLReflowMetrics captionMet(PR_FALSE);
01979       nsReflowReason reason = aOuterRS.reason;
01980       if (eReflowReason_Initial == aOuterRS.reason) {
01981         reason = eReflowReason_Resize; // we have already done the initial reflow
01982       }
01983       nsReflowStatus capStatus; // don't let the caption cause incomplete
01984       rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, 
01985                             availCaptionWidth, captionSize, captionMargin, captionMarginNoAuto,
01986                             ignorePadding, reason, capStatus);
01987       if (NS_FAILED(rv)) return rv;
01988 
01989       nsPoint captionOrigin;
01990 
01991       GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, 
01992                        innerMargin, captionSize, captionMargin, captionOrigin);
01993       FinishReflowChild(mCaptionFrame, aPresContext, nsnull, captionMet,
01994                         captionOrigin.x, captionOrigin.y, 0);
01995 
01996       GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
01997                      captionMargin, innerSize, innerMargin, innerOrigin);
01998 
01999       // XXX If the height is constrained then we need to check whether the inner table still fits...
02000     } 
02001     else {
02002       GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, 
02003                      captionMargin, innerSize, innerMargin, innerOrigin);
02004     }
02005 
02006     FinishReflowChild(mInnerTableFrame, aPresContext, nsnull, innerMet,
02007                       innerOrigin.x, innerOrigin.y, 0);
02008     if (aDesiredSize.mComputeMEW) {
02009       aDesiredSize.mMaxElementWidth = innerMet.mMaxElementWidth;
02010     }
02011 
02012     UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, 
02013                         innerPadding, captionMargin, captionMarginNoAuto, aOuterRS.availableWidth);
02014     needUpdateMetrics = PR_FALSE;
02015   }
02016   
02017   // Return our desired rect
02018   aDesiredSize.ascent  = aDesiredSize.height;
02019   aDesiredSize.descent = 0;
02020 
02021   // compute max element size and maximum width if it hasn't already been 
02022   if (needUpdateMetrics) {
02023     nsMargin innerMargin, innerMarginNoAuto, capMargin(0,0,0,0), 
02024              capMarginNoAuto(0,0,0,0), innerPadding, capPadding(0,0,0,0);
02025     GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, aOuterRS.availableWidth, 
02026                      innerMargin, innerMarginNoAuto, innerPadding);
02027     if (mCaptionFrame) {
02028       nscoord outerWidth;
02029       switch (captionSide) {
02030         case NS_SIDE_LEFT: 
02031           outerWidth = innerMargin.left;
02032           break;
02033         case NS_SIDE_RIGHT:
02034           outerWidth = innerMargin.right;
02035           break;
02036         default:
02037           outerWidth = aOuterRS.availableWidth;
02038           break;
02039       }
02040       GetMarginPadding(aPresContext, aOuterRS, mCaptionFrame, outerWidth,
02041                        capMargin, capMarginNoAuto, capPadding);
02042     }
02043     UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerMarginNoAuto, 
02044                         innerPadding, capMargin, capMarginNoAuto, aOuterRS.availableWidth);
02045   }
02046 #ifdef CHECK_THIS_AND_REMOVE
02047   // See if we are supposed to compute our maximum width
02048   if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
02049     // XXX this needs to consider the possibility of a caption being wider 
02050     // than the inner table, but this is the safest way to fix bug 55545
02051     if (mInnerTableFrame) {
02052       aDesiredSize.mMaximumWidth = ((nsTableFrame*)mInnerTableFrame)->GetPreferredWidth();
02053     }
02054   }
02055 #endif
02056 
02057   mPriorAvailWidth = aOuterRS.availableWidth;
02058 
02059 #if defined DEBUG_TABLE_REFLOW_TIMING
02060   nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS, &aDesiredSize, aStatus);
02061 #endif
02062   NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize);
02063   return rv;
02064 }
02065 
02066 NS_METHOD nsTableOuterFrame::VerifyTree() const
02067 {
02068   return NS_OK;
02069 }
02070 
02084 void nsTableOuterFrame::DeleteChildsNextInFlow(nsPresContext* aPresContext, 
02085                                                nsIFrame*       aChild)
02086 {
02087   if (!aChild) return;
02088   NS_PRECONDITION(mFrames.ContainsFrame(aChild), "bad geometric parent");
02089 
02090   nsIFrame* nextInFlow = aChild->GetNextInFlow();
02091   if (!nextInFlow) {
02092     NS_ASSERTION(PR_FALSE, "null next-in-flow");
02093     return;
02094   }
02095 
02096   nsTableOuterFrame* parent = NS_STATIC_CAST(nsTableOuterFrame*,
02097                                              nextInFlow->GetParent());
02098   if (!parent) {
02099     NS_ASSERTION(PR_FALSE, "null parent");
02100     return;
02101   }
02102   // If the next-in-flow has a next-in-flow then delete it too (and
02103   // delete it first).
02104   nsIFrame* nextNextInFlow = nextInFlow->GetNextInFlow();
02105   if (nextNextInFlow) {
02106     parent->DeleteChildsNextInFlow(aPresContext, nextInFlow);
02107   }
02108 
02109   // Disconnect the next-in-flow from the flow list
02110   nsSplittableFrame::BreakFromPrevFlow(nextInFlow);
02111 
02112   // Take the next-in-flow out of the parent's child list
02113   if (parent->mFrames.FirstChild() == nextInFlow) {
02114     parent->mFrames.SetFrames(nextInFlow->GetNextSibling());
02115   } else {
02116     // Because the next-in-flow is not the first child of the parent
02117     // we know that it shares a parent with aChild. Therefore, we need
02118     // to capture the next-in-flow's next sibling (in case the
02119     // next-in-flow is the last next-in-flow for aChild AND the
02120     // next-in-flow is not the last child in parent)
02121     NS_ASSERTION(aChild->GetNextSibling() == nextInFlow, "unexpected sibling");
02122 
02123     aChild->SetNextSibling(nextInFlow->GetNextSibling());
02124   }
02125 
02126   // Delete the next-in-flow frame and adjust it's parent's child count
02127   nextInFlow->Destroy(aPresContext);
02128 
02129   NS_POSTCONDITION(!aChild->GetNextInFlow(), "non null next-in-flow");
02130 }
02131 
02132 nsIAtom*
02133 nsTableOuterFrame::GetType() const
02134 {
02135   return nsLayoutAtoms::tableOuterFrame;
02136 }
02137 
02138 /* ----- global methods ----- */
02139 
02140 /*------------------ nsITableLayout methods ------------------------------*/
02141 NS_IMETHODIMP 
02142 nsTableOuterFrame::GetCellDataAt(PRInt32 aRowIndex, PRInt32 aColIndex, 
02143                                  nsIDOMElement* &aCell,   //out params
02144                                  PRInt32& aStartRowIndex, PRInt32& aStartColIndex, 
02145                                  PRInt32& aRowSpan, PRInt32& aColSpan,
02146                                  PRInt32& aActualRowSpan, PRInt32& aActualColSpan,
02147                                  PRBool& aIsSelected)
02148 {
02149   if (!mInnerTableFrame) { return NS_ERROR_NOT_INITIALIZED; }
02150   nsITableLayout *inner;
02151   if (NS_SUCCEEDED(CallQueryInterface(mInnerTableFrame, &inner))) {
02152     return (inner->GetCellDataAt(aRowIndex, aColIndex, aCell,
02153                                  aStartRowIndex, aStartColIndex, 
02154                                  aRowSpan, aColSpan, aActualRowSpan, aActualColSpan, 
02155                                  aIsSelected));
02156   }
02157   return NS_ERROR_NULL_POINTER;
02158 }
02159 
02160 NS_IMETHODIMP nsTableOuterFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)
02161 {
02162   if (!mInnerTableFrame) { return NS_ERROR_NOT_INITIALIZED; }
02163   nsITableLayout *inner;
02164   if (NS_SUCCEEDED(CallQueryInterface(mInnerTableFrame, &inner))) {
02165     return (inner->GetTableSize(aRowCount, aColCount));
02166   }
02167   return NS_ERROR_NULL_POINTER;
02168 }
02169 
02170 /*---------------- end of nsITableLayout implementation ------------------*/
02171 
02172 
02173 nsresult 
02174 NS_NewTableOuterFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
02175 {
02176   NS_PRECONDITION(aNewFrame, "null OUT ptr");
02177   if (nsnull == aNewFrame) {
02178     return NS_ERROR_NULL_POINTER;
02179   }
02180   nsTableOuterFrame* it = new (aPresShell) nsTableOuterFrame;
02181   if (nsnull == it) {
02182     return NS_ERROR_OUT_OF_MEMORY;
02183   }
02184   *aNewFrame = it;
02185   return NS_OK;
02186 }
02187 
02188 #ifdef DEBUG
02189 NS_IMETHODIMP
02190 nsTableOuterFrame::GetFrameName(nsAString& aResult) const
02191 {
02192   return MakeFrameName(NS_LITERAL_STRING("TableOuter"), aResult);
02193 }
02194 #endif
02195