Back to index

lightning-sunbird  0.9+nobinonly
nsTableCellFrame.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 "nsTableFrame.h"
00039 #include "nsTableColFrame.h"
00040 #include "nsTableCellFrame.h"
00041 #include "nsTableFrame.h"
00042 #include "nsTableRowGroupFrame.h"
00043 #include "nsTablePainter.h"
00044 #include "nsReflowPath.h"
00045 #include "nsStyleContext.h"
00046 #include "nsStyleConsts.h"
00047 #include "nsPresContext.h"
00048 #include "nsIRenderingContext.h"
00049 #include "nsCSSRendering.h"
00050 #include "nsIContent.h"
00051 #include "nsGenericHTMLElement.h"
00052 #include "nsHTMLParts.h"
00053 #include "nsHTMLAtoms.h"
00054 #include "nsVoidArray.h"
00055 #include "nsIView.h"
00056 #include "nsLayoutAtoms.h"
00057 #include "nsIPresShell.h"
00058 #include "nsCOMPtr.h"
00059 #include "nsIDOMHTMLTableCellElement.h"
00060 #ifdef ACCESSIBILITY
00061 #include "nsIAccessibilityService.h"
00062 #endif
00063 #include "nsIServiceManager.h"
00064 #include "nsIDOMNode.h"
00065 #include "nsINameSpaceManager.h"
00066 
00067 
00068 //TABLECELL SELECTION
00069 #include "nsIFrameSelection.h"
00070 #include "nsILookAndFeel.h"
00071 
00072 
00073 nsTableCellFrame::nsTableCellFrame()
00074 {
00075   mBits.mColIndex  = 0;
00076   mPriorAvailWidth = 0;
00077 
00078   SetContentEmpty(PR_FALSE);
00079   SetNeedSpecialReflow(PR_FALSE);
00080   SetHadSpecialReflow(PR_FALSE);
00081   SetHasPctOverHeight(PR_FALSE);
00082   SetNeedPass2Reflow(PR_TRUE);
00083 
00084 #ifdef DEBUG_TABLE_REFLOW_TIMING
00085   mTimer = new nsReflowTimer(this);
00086   mBlockTimer = new nsReflowTimer(this);
00087 #endif
00088 }
00089 
00090 nsTableCellFrame::~nsTableCellFrame()
00091 {
00092 #ifdef DEBUG_TABLE_REFLOW_TIMING
00093   nsTableFrame::DebugReflowDone(this);
00094 #endif
00095 }
00096 
00097 nsTableCellFrame*  
00098 nsTableCellFrame::GetNextCell() const
00099 {
00100   nsIFrame* childFrame = GetNextSibling();
00101   while (childFrame) {
00102     if (IS_TABLE_CELL(childFrame->GetType())) {
00103       return (nsTableCellFrame*)childFrame;
00104     }
00105     childFrame = childFrame->GetNextSibling();
00106   }
00107   return nsnull;
00108 }
00109 
00110 NS_IMETHODIMP
00111 nsTableCellFrame::Init(nsPresContext*  aPresContext,
00112                        nsIContent*      aContent,
00113                        nsIFrame*        aParent,
00114                        nsStyleContext*  aContext,
00115                        nsIFrame*        aPrevInFlow)
00116 {
00117   nsresult  rv;
00118   
00119   // Let the base class do its initialization
00120   rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext,
00121                                   aPrevInFlow);
00122 
00123   if (aPrevInFlow) {
00124     // Set the column index
00125     nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
00126     PRInt32           colIndex;
00127     cellFrame->GetColIndex(colIndex);
00128     SetColIndex(colIndex);
00129   }
00130 
00131   return rv;
00132 }
00133 
00134 // nsIPercentHeightObserver methods
00135 
00136 void
00137 nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
00138 {
00139   if (!NeedSpecialReflow()) {
00140     // Only initiate a special reflow if we will be able to construct a computed height 
00141     // on the cell that will result in the frame getting a computed height. This can only 
00142     // happen (but not sufficient) if there is no computed height already set between the 
00143     // initiating frame and the cell.
00144     for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) {
00145       if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) {
00146         return;
00147       }
00148       // stop when we reach the cell frame
00149       if (rs->frame == this) {
00150         nsTableFrame::RequestSpecialHeightReflow(*rs);
00151         return;
00152       }
00153     }
00154     NS_ASSERTION(PR_FALSE, "program error in NotifyPercentHeight");
00155   }
00156 }
00157 
00158 // The cell needs to observe its block and things inside its block but nothing below that
00159 PRBool 
00160 nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState)
00161 {
00162   PRBool result = PR_FALSE;
00163   const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
00164   if (parentRS && (parentRS->mPercentHeightObserver == this)) { // cell observes the parent
00165     result = PR_TRUE;
00166     parentRS = parentRS->parentReflowState;
00167     if (parentRS && (parentRS->mPercentHeightObserver == this)) { // cell observers the grand parent
00168       parentRS = parentRS->parentReflowState;
00169       if (parentRS && (parentRS->mPercentHeightObserver == this)) { 
00170         // cell observes the great grand parent, so we have gone too deep
00171         result = PR_FALSE;
00172       }
00173     }
00174   }
00175   return result;
00176 }
00177 
00178 nsresult 
00179 nsTableCellFrame::GetRowIndex(PRInt32 &aRowIndex) const
00180 {
00181   nsresult result;
00182   nsTableRowFrame* row = NS_STATIC_CAST(nsTableRowFrame*, GetParent());
00183   if (row) {
00184     aRowIndex = row->GetRowIndex();
00185     result = NS_OK;
00186   }
00187   else {
00188     aRowIndex = 0;
00189     result = NS_ERROR_NOT_INITIALIZED;
00190   }
00191   return result;
00192 }
00193 
00194 nsresult 
00195 nsTableCellFrame::GetColIndex(PRInt32 &aColIndex) const
00196 {  
00197   if (mPrevInFlow) {
00198     return ((nsTableCellFrame*)GetFirstInFlow())->GetColIndex(aColIndex);
00199   }
00200   else {
00201     aColIndex = mBits.mColIndex;
00202     return  NS_OK;
00203   }
00204 }
00205 
00206 NS_IMETHODIMP
00207 nsTableCellFrame::AttributeChanged(nsIContent*     aChild,
00208                                    PRInt32         aNameSpaceID,
00209                                    nsIAtom*        aAttribute,
00210                                    PRInt32         aModType)
00211 {
00212   // let the table frame decide what to do
00213   nsTableFrame* tableFrame = nsnull; 
00214   nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
00215   if ((NS_SUCCEEDED(rv)) && (tableFrame)) {
00216     tableFrame->AttributeChangedFor(this, aChild, aAttribute); 
00217   }
00218   return NS_OK;
00219 }
00220 
00221 void nsTableCellFrame::SetPass1MaxElementWidth(nscoord aMaxWidth,
00222                                                nscoord aMaxElementWidth)
00223 { 
00224   nscoord maxElemWidth = aMaxElementWidth;
00225   if (eCompatibility_NavQuirks == GetPresContext()->CompatibilityMode()) {
00226     // check for fixed width and not nowrap and not pre
00227     const nsStylePosition* stylePosition = GetStylePosition();
00228     if (stylePosition->mWidth.GetUnit() == eStyleUnit_Coord) {
00229       if (GetContent()->HasAttr(kNameSpaceID_None, nsHTMLAtoms::nowrap)) {
00230         // set the max element size to the value of the fixed width (NAV/IE quirk)
00231         maxElemWidth = NS_MAX(maxElemWidth, stylePosition->mWidth.GetCoordValue());
00232       }
00233     }
00234   }
00235   mPass1MaxElementWidth = maxElemWidth;
00236 }
00237 
00238 NS_IMETHODIMP
00239 nsTableCellFrame::AppendFrames(nsIAtom*        aListName,
00240                                nsIFrame*       aFrameList)
00241 {
00242   NS_PRECONDITION(PR_FALSE, "unsupported operation");
00243   return NS_ERROR_NOT_IMPLEMENTED;
00244 }
00245 
00246 NS_IMETHODIMP
00247 nsTableCellFrame::InsertFrames(nsIAtom*        aListName,
00248                                nsIFrame*       aPrevFrame,
00249                                nsIFrame*       aFrameList)
00250 {
00251   NS_PRECONDITION(PR_FALSE, "unsupported operation");
00252   return NS_ERROR_NOT_IMPLEMENTED;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsTableCellFrame::RemoveFrame(nsIAtom*        aListName,
00257                               nsIFrame*       aOldFrame)
00258 {
00259   NS_PRECONDITION(PR_FALSE, "unsupported operation");
00260   return NS_ERROR_NOT_IMPLEMENTED;
00261 }
00262 
00263 void nsTableCellFrame::SetColIndex(PRInt32 aColIndex)
00264 {  
00265   mBits.mColIndex = aColIndex;
00266 }
00267 
00268 
00269 //ASSURE DIFFERENT COLORS for selection
00270 inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB)
00271 {
00272     if (colorA == colorB)
00273     {
00274       nscolor res;
00275       res = NS_RGB(NS_GET_R(colorA) ^ 0xff,
00276                    NS_GET_G(colorA) ^ 0xff,
00277                    NS_GET_B(colorA) ^ 0xff);
00278       return res;
00279     }
00280     return colorA;
00281 }
00282 
00283 
00284 nsresult
00285 nsTableCellFrame::DecorateForSelection(nsPresContext* aPresContext,
00286                                        nsIRenderingContext& aRenderingContext,
00287                                        const nsStyleBackground *aStyleColor)
00288 {
00289   PRInt16 displaySelection;
00290   displaySelection = DisplaySelection(aPresContext);
00291   if (displaySelection) {
00292     PRBool isSelected =
00293       (GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
00294     if (isSelected) {
00295       nsIFrameSelection *frameSelection =
00296         aPresContext->PresShell()->FrameSelection();
00297 
00298       PRBool tableCellSelectionMode;
00299       nsresult result =
00300         frameSelection->GetTableCellSelection(&tableCellSelectionMode);
00301       if (NS_SUCCEEDED(result) && tableCellSelectionMode) {
00302         nscolor       bordercolor;
00303         if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
00304           bordercolor = NS_RGB(176,176,176);// disabled color
00305         }
00306         else {
00307           aPresContext->LookAndFeel()->
00308             GetColor(nsILookAndFeel::eColor_TextSelectBackground,
00309                      bordercolor);
00310         }
00311         PRInt16 t2p = (PRInt16) aPresContext->PixelsToTwips();
00312         if ((mRect.width >(3*t2p)) && (mRect.height > (3*t2p)))
00313         {
00314           //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
00315           bordercolor = EnsureDifferentColors(bordercolor, aStyleColor->mBackgroundColor);
00316           //outerrounded
00317           aRenderingContext.SetColor(bordercolor);
00318           aRenderingContext.DrawLine(t2p, 0, mRect.width, 0);
00319           aRenderingContext.DrawLine(0, t2p, 0, mRect.height);
00320           aRenderingContext.DrawLine(t2p, mRect.height, mRect.width, mRect.height);
00321           aRenderingContext.DrawLine(mRect.width, t2p, mRect.width, mRect.height);
00322           //middle
00323           aRenderingContext.DrawRect(t2p, t2p, mRect.width-t2p, mRect.height-t2p);
00324           //shading
00325           aRenderingContext.DrawLine(2*t2p, mRect.height-2*t2p, mRect.width-t2p, mRect.height- (2*t2p));
00326           aRenderingContext.DrawLine(mRect.width - (2*t2p), 2*t2p, mRect.width - (2*t2p), mRect.height-t2p);
00327         }
00328       }
00329     }
00330   }
00331   return NS_OK;
00332 }
00333 
00334 void
00335 nsTableCellFrame::PaintUnderlay(nsPresContext&           aPresContext,
00336                                 nsIRenderingContext&      aRenderingContext,
00337                                 const nsRect&             aDirtyRect,
00338                                 PRUint32&                 aFlags,
00339                                 const nsStyleBorder&      aStyleBorder,
00340                                 const nsStylePadding&     aStylePadding,
00341                                 const nsStyleTableBorder& aCellTableStyle)
00342 {
00343   nsRect rect(0, 0, mRect.width, mRect.height);
00344   nsCSSRendering::PaintBackground(&aPresContext, aRenderingContext, this,
00345                                   aDirtyRect, rect, aStyleBorder, aStylePadding,
00346                                   PR_TRUE);
00347   PRIntn skipSides = GetSkipSides();
00348   if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW == aCellTableStyle.mEmptyCells ||
00349       !GetContentEmpty()) {
00350     nsCSSRendering::PaintBorder(&aPresContext, aRenderingContext, this,
00351                                 aDirtyRect, rect, aStyleBorder, mStyleContext, skipSides);
00352   }
00353 }
00354 
00355 NS_IMETHODIMP
00356 nsTableCellFrame::Paint(nsPresContext*      aPresContext,
00357                         nsIRenderingContext& aRenderingContext,
00358                         const nsRect&        aDirtyRect,
00359                         nsFramePaintLayer    aWhichLayer,
00360                         PRUint32             aFlags)
00361 {
00362   NS_ENSURE_TRUE(aPresContext, NS_ERROR_NULL_POINTER);
00363   PRBool isVisible;
00364   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_FALSE, &isVisible)) && !isVisible) {
00365     return NS_OK;
00366   }
00367 
00368   PRBool paintChildren = PR_TRUE;
00369 
00370   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00371     const nsStyleBorder*      myBorder       = nsnull;
00372     const nsStylePadding*     myPadding      = nsnull;
00373     const nsStyleTableBorder* cellTableStyle = nsnull;
00374     const nsStyleVisibility* vis = GetStyleVisibility();
00375     if (vis->IsVisible()) {
00376       myBorder = GetStyleBorder();
00377       myPadding = GetStylePadding();
00378       cellTableStyle = GetStyleTableBorder();
00379 
00380       // draw the border & background only when there is content or showing empty cells
00381       if (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != cellTableStyle->mEmptyCells ||
00382           !GetContentEmpty()) {
00383         PaintUnderlay(*aPresContext, aRenderingContext, aDirtyRect, aFlags,
00384                       *myBorder, *myPadding, *cellTableStyle);
00385       }
00386 
00387       // Paint outline
00388       nsRect rect(0, 0, mRect.width, mRect.height);
00389       const nsStyleOutline* myOutline = GetStyleOutline();
00390       nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
00391                                   aDirtyRect, rect, *myBorder, *myOutline,
00392                                   mStyleContext, 0);
00393 
00394       const nsStyleBackground* myColor = GetStyleBackground();
00395       DecorateForSelection(aPresContext, aRenderingContext,myColor); //ignore return value
00396     }
00397 
00398     paintChildren = !(aFlags & NS_PAINT_FLAG_TABLE_CELL_BG_PASS);
00399     //flags were for us; remove them for our children
00400     aFlags &= ~ (NS_PAINT_FLAG_TABLE_CELL_BG_PASS | NS_PAINT_FLAG_TABLE_BG_PAINT);
00401   }
00402 
00403 #ifdef DEBUG
00404   // for debug...
00405   if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
00406     aRenderingContext.SetColor(NS_RGB(0, 0, 128));
00407     aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
00408   }
00409 #endif
00410 
00411   // paint the children unless we've been told not to
00412   if (paintChildren) {
00413     const nsStyleDisplay* disp = GetStyleDisplay();
00414     // if the cell originates in a row and/or col that is collapsed, the
00415     // bottom and/or right portion of the cell is painted by translating
00416     // the rendering context.
00417     nsPoint offset;
00418     GetCollapseOffset(offset);
00419     PRBool pushed = PR_FALSE;
00420     if ((0 != offset.x) || (0 != offset.y)) {
00421       aRenderingContext.PushState();
00422       pushed = PR_TRUE;
00423       aRenderingContext.Translate(offset.x, offset.y);
00424       aRenderingContext.SetClipRect(nsRect(-offset.x, -offset.y, mRect.width, mRect.height),
00425                                     nsClipCombine_kIntersect);
00426     }
00427     else {
00428       // XXXldb HIDDEN should really create a scrollframe,
00429       // but use |IsTableClip| here since it doesn't.
00430       if (disp->IsTableClip() ||
00431           (HasPctOverHeight() && eCompatibility_NavQuirks == aPresContext->CompatibilityMode())) {
00432         aRenderingContext.PushState();
00433         pushed = PR_TRUE;
00434         SetOverflowClipRect(aRenderingContext);
00435       }    
00436     }
00437 
00438     PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags);
00439 
00440     if (pushed) {
00441       aRenderingContext.PopState();
00442     }
00443   } 
00444   
00445   DO_GLOBAL_REFLOW_COUNT_DSP_J("nsTableCellFrame", &aRenderingContext, 0);
00446   return NS_OK;
00447   /*nsFrame::Paint(aPresContext,
00448                         aRenderingContext,
00449                         aDirtyRect,
00450                         aWhichLayer);*/
00451 }
00452 
00453 NS_IMETHODIMP
00454 nsTableCellFrame::GetFrameForPoint(const nsPoint&    aPoint, 
00455                                    nsFramePaintLayer aWhichLayer,
00456                                    nsIFrame**        aFrame)
00457 {
00458   // this should act like a block, so we need to override
00459   return GetFrameForPointUsing(aPoint, nsnull, aWhichLayer, (aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND), aFrame);
00460 }
00461 
00462 //null range means the whole thing
00463 NS_IMETHODIMP
00464 nsTableCellFrame::SetSelected(nsPresContext* aPresContext,
00465                               nsIDOMRange*    aRange,
00466                               PRBool          aSelected,
00467                               nsSpread        aSpread)
00468 {
00469   //traverse through children unselect tables
00470 #if 0
00471   if ((aSpread == eSpreadDown)){
00472     nsIFrame* kid = GetFirstChild(nsnull);
00473     while (nsnull != kid) {
00474       kid->SetSelected(nsnull, aSelected, eSpreadDown);
00475       kid = kid->GetNextSibling();
00476     }
00477   }
00478   //return nsFrame::SetSelected(aRange,aSelected,eSpreadNone);
00479 #endif
00480   // Must call base class to set mSelected state and trigger repaint of frame
00481   // Note that in current version, aRange and aSpread are ignored,
00482   //   only this frame is considered
00483   nsFrame::SetSelected(aPresContext, aRange, aSelected, aSpread);
00484 
00485   PRBool tableCellSelectionMode;
00486   nsresult result = aPresContext->PresShell()->FrameSelection()->GetTableCellSelection(&tableCellSelectionMode);
00487   if (NS_SUCCEEDED(result) && tableCellSelectionMode) {
00488     // Selection can affect content, border and outline
00489     Invalidate(GetOverflowRect(), PR_FALSE);
00490   }
00491   return NS_OK;
00492 }
00493 
00494 PRIntn
00495 nsTableCellFrame::GetSkipSides() const
00496 {
00497   PRIntn skip = 0;
00498   if (nsnull != mPrevInFlow) {
00499     skip |= 1 << NS_SIDE_TOP;
00500   }
00501   if (nsnull != mNextInFlow) {
00502     skip |= 1 << NS_SIDE_BOTTOM;
00503   }
00504   return skip;
00505 }
00506 
00507 PRBool nsTableCellFrame::ParentDisablesSelection() const //override default behavior
00508 {
00509   PRBool returnval;
00510   if (NS_FAILED(GetSelected(&returnval)))
00511     return PR_FALSE;
00512   if (returnval)
00513     return PR_TRUE;
00514   return nsFrame::ParentDisablesSelection();
00515 }
00516 
00517 /* virtual */ void
00518 nsTableCellFrame::GetSelfOverflow(nsRect& aOverflowArea)
00519 {
00520   aOverflowArea = nsRect(nsPoint(0,0), GetSize());
00521 }
00522 
00523 // Align the cell's child frame within the cell
00524 
00525 void nsTableCellFrame::VerticallyAlignChild(const nsHTMLReflowState& aReflowState,
00526                                             nscoord                  aMaxAscent)
00527 {
00528   const nsStyleTextReset* textStyle = GetStyleTextReset();
00529   /* XXX: remove tableFrame when border-collapse inherits */
00530   nsPresContext* presContext = GetPresContext();
00531   GET_PIXELS_TO_TWIPS(presContext, p2t);
00532   nsMargin borderPadding = nsTableFrame::GetBorderPadding(aReflowState, p2t, this);
00533   
00534   nscoord topInset = borderPadding.top;
00535   nscoord bottomInset = borderPadding.bottom;
00536 
00537   // As per bug 10207, we map 'sub', 'super', 'text-top', 'text-bottom', 
00538   // length and percentage values to 'baseline'
00539   // XXX It seems that we don't get to see length and percentage values here
00540   //     because the Style System has already fixed the error and mapped them
00541   //     to whatever is inherited from the parent, i.e, 'middle' in most cases.
00542   PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_BASELINE;
00543   if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) {
00544     verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue();
00545     if (verticalAlignFlags != NS_STYLE_VERTICAL_ALIGN_TOP &&
00546         verticalAlignFlags != NS_STYLE_VERTICAL_ALIGN_MIDDLE &&
00547         verticalAlignFlags != NS_STYLE_VERTICAL_ALIGN_BOTTOM)
00548     {
00549       verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_BASELINE;
00550     }
00551   }
00552 
00553   nscoord height = mRect.height;
00554   nsIFrame* firstKid = mFrames.FirstChild();
00555   NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
00556   nsRect kidRect = firstKid->GetRect();
00557   nscoord childHeight = kidRect.height;
00558 
00559   // Vertically align the child
00560   nscoord kidYTop = 0;
00561   switch (verticalAlignFlags) 
00562   {
00563     case NS_STYLE_VERTICAL_ALIGN_BASELINE:
00564       // Align the baselines of the child frame with the baselines of 
00565       // other children in the same row which have 'vertical-align: baseline'
00566       kidYTop = topInset + aMaxAscent - GetDesiredAscent();
00567     break;
00568 
00569     case NS_STYLE_VERTICAL_ALIGN_TOP:
00570       // Align the top of the child frame with the top of the content area, 
00571       kidYTop = topInset;
00572     break;
00573 
00574     case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
00575       // Align the bottom of the child frame with the bottom of the content area, 
00576       kidYTop = height - childHeight - bottomInset;
00577     break;
00578 
00579     default:
00580     case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
00581       // Align the middle of the child frame with the middle of the content area, 
00582       kidYTop = (height - childHeight - bottomInset + topInset) / 2;
00583       kidYTop = nsTableFrame::RoundToPixel(kidYTop,
00584                                            presContext->ScaledPixelsToTwips(),
00585                                            eAlwaysRoundDown);
00586   }
00587   // if the content is larger than the cell height align from top
00588   kidYTop = PR_MAX(0, kidYTop);
00589 
00590   firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
00591   nsHTMLReflowMetrics desiredSize(PR_FALSE);
00592   desiredSize.width = mRect.width;
00593   desiredSize.height = mRect.height;
00594   GetSelfOverflow(desiredSize.mOverflowArea);
00595   ConsiderChildOverflow(desiredSize.mOverflowArea, firstKid);
00596   FinishAndStoreOverflow(&desiredSize);
00597   if (kidYTop != kidRect.y) {
00598     // Make sure any child views are correctly positioned. We know the inner table
00599     // cell won't have a view
00600     nsContainerFrame::PositionChildViews(firstKid);
00601   }
00602   if (HasView()) {
00603     nsContainerFrame::SyncFrameViewAfterReflow(presContext, this,
00604                                                GetView(),
00605                                                &desiredSize.mOverflowArea, 0);
00606   }
00607 }
00608 
00609 // As per bug 10207, we map 'sub', 'super', 'text-top', 'text-bottom', 
00610 // length and percentage values to 'baseline'
00611 // XXX It seems that we don't get to see length and percentage values here
00612 //     because the Style System has already fixed the error and mapped them
00613 //     to whatever is inherited from the parent, i.e, 'middle' in most cases.
00614 PRBool
00615 nsTableCellFrame::HasVerticalAlignBaseline()
00616 {
00617   const nsStyleTextReset* textStyle = GetStyleTextReset();
00618   if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) {
00619     PRUint8 verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue();
00620     if (verticalAlignFlags == NS_STYLE_VERTICAL_ALIGN_TOP ||
00621         verticalAlignFlags == NS_STYLE_VERTICAL_ALIGN_MIDDLE ||
00622         verticalAlignFlags == NS_STYLE_VERTICAL_ALIGN_BOTTOM)
00623     {
00624       return PR_FALSE;
00625     }
00626   }
00627   return PR_TRUE;
00628 }
00629 
00630 PRInt32 nsTableCellFrame::GetRowSpan()
00631 {  
00632   PRInt32 rowSpan=1;
00633   nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
00634 
00635   if (hc) {
00636     const nsAttrValue* attr = hc->GetParsedAttr(nsHTMLAtoms::rowspan); 
00637     if (attr && attr->Type() == nsAttrValue::eInteger) { 
00638        rowSpan = attr->GetIntegerValue(); 
00639     }
00640   }
00641   return rowSpan;
00642 }
00643 
00644 PRInt32 nsTableCellFrame::GetColSpan()
00645 {  
00646   PRInt32 colSpan=1;
00647   nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
00648 
00649   if (hc) {
00650     const nsAttrValue* attr = hc->GetParsedAttr(nsHTMLAtoms::colspan); 
00651     if (attr && attr->Type() == nsAttrValue::eInteger) { 
00652        colSpan = attr->GetIntegerValue(); 
00653     }
00654   }
00655   return colSpan;
00656 }
00657 
00658 #ifdef DEBUG
00659 #define PROBABLY_TOO_LARGE 1000000
00660 static
00661 void DebugCheckChildSize(nsIFrame*            aChild, 
00662                          nsHTMLReflowMetrics& aMet, 
00663                          nsSize&              aAvailSize,
00664                          PRBool               aIsPass2Reflow)
00665 {
00666   if (aIsPass2Reflow) {
00667     if ((aMet.width < 0) || (aMet.width > PROBABLY_TOO_LARGE)) {
00668       printf("WARNING: cell content %p has large width %d \n", aChild, aMet.width);
00669     }
00670   }
00671   if (aMet.mComputeMEW) {
00672     nscoord tmp = aMet.mMaxElementWidth;
00673     if ((tmp < 0) || (tmp > PROBABLY_TOO_LARGE)) {
00674       printf("WARNING: cell content %p has large max element width %d \n", aChild, tmp);
00675     }
00676   }
00677 }
00678 #endif
00679 
00680 // the computed height for the cell, which descendents use for percent height calculations
00681 // it is the height (minus border, padding) of the cell's first in flow during its final 
00682 // reflow without an unconstrained height.
00683 static nscoord
00684 CalcUnpaginagedHeight(nsPresContext*       aPresContext,
00685                       nsTableCellFrame&     aCellFrame, 
00686                       nsTableFrame&         aTableFrame,
00687                       nscoord               aVerticalBorderPadding)
00688 {
00689   const nsTableCellFrame* firstCellInFlow   = (nsTableCellFrame*)aCellFrame.GetFirstInFlow();
00690   nsTableFrame*           firstTableInFlow  = (nsTableFrame*)aTableFrame.GetFirstInFlow();
00691   nsTableRowFrame*        row
00692     = NS_STATIC_CAST(nsTableRowFrame*, firstCellInFlow->GetParent());
00693   nsTableRowGroupFrame*   firstRGInFlow
00694     = NS_STATIC_CAST(nsTableRowGroupFrame*, row->GetParent());
00695 
00696   PRInt32 rowIndex;
00697   firstCellInFlow->GetRowIndex(rowIndex);
00698   PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
00699   nscoord cellSpacing = firstTableInFlow->GetCellSpacingX();
00700 
00701   nscoord computedHeight = ((rowSpan - 1) * cellSpacing) - aVerticalBorderPadding;
00702   PRInt32 rowX;
00703   for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) {
00704     if (rowX > rowIndex + rowSpan - 1) {
00705       break;
00706     }
00707     else if (rowX >= rowIndex) {
00708       computedHeight += row->GetUnpaginatedHeight(aPresContext);
00709     }
00710   }
00711   return computedHeight;
00712 }
00713 
00714 NS_METHOD nsTableCellFrame::Reflow(nsPresContext*          aPresContext,
00715                                    nsHTMLReflowMetrics&     aDesiredSize,
00716                                    const nsHTMLReflowState& aReflowState,
00717                                    nsReflowStatus&          aStatus)
00718 {
00719   DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame", aReflowState.reason);
00720   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00721 #if defined DEBUG_TABLE_REFLOW_TIMING
00722   nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
00723 #endif
00724   float p2t = aPresContext->ScaledPixelsToTwips();
00725 
00726   // work around pixel rounding errors, round down to ensure we don't exceed the avail height in
00727   nscoord availHeight = aReflowState.availableHeight;
00728   if (NS_UNCONSTRAINEDSIZE != availHeight) {
00729     availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown);
00730   }
00731 
00732   nsresult rv = NS_OK;
00733 
00734   // see if a special height reflow needs to occur due to having a pct height
00735   if (!NeedSpecialReflow()) 
00736     nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
00737 
00738   // this should probably be cached somewhere
00739   nsCompatibility compatMode = aPresContext->CompatibilityMode();
00740 
00741   // Initialize out parameter
00742   if (aDesiredSize.mComputeMEW) {
00743     aDesiredSize.mMaxElementWidth = 0;
00744   }
00745 
00746   aStatus = NS_FRAME_COMPLETE;
00747   nsSize availSize(aReflowState.availableWidth, availHeight);
00748 
00749   PRBool noBorderBeforeReflow = GetContentEmpty() &&
00750     GetStyleTableBorder()->mEmptyCells != NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
00751   /* XXX: remove tableFrame when border-collapse inherits */
00752   nsTableFrame* tableFrame = nsnull;
00753   rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER);
00754 
00755   nsMargin borderPadding = aReflowState.mComputedPadding;
00756   nsMargin border;
00757   GetBorderWidth(p2t, border);
00758   if ((NS_UNCONSTRAINEDSIZE == availSize.width) || !noBorderBeforeReflow) {
00759     borderPadding += border;
00760   }
00761   
00762   nscoord topInset    = borderPadding.top;
00763   nscoord rightInset  = borderPadding.right;
00764   nscoord bottomInset = borderPadding.bottom;
00765   nscoord leftInset   = borderPadding.left;
00766 
00767   // reduce available space by insets, if we're in a constrained situation
00768   if (NS_UNCONSTRAINEDSIZE!=availSize.width)
00769     availSize.width -= leftInset+rightInset;
00770   if (NS_UNCONSTRAINEDSIZE!=availSize.height)
00771     availSize.height -= topInset+bottomInset;
00772 
00773   PRBool  isStyleChanged = PR_FALSE;
00774   if (eReflowReason_Incremental == aReflowState.reason) {
00775     // if the path has a reflow command then the cell must be the target of a style change 
00776     nsHTMLReflowCommand* command = aReflowState.path->mReflowCommand;
00777     if (command) {
00778       // if there are other reflow commands targeted at the cell's block, these will
00779       // be subsumed by the style change reflow
00780       nsReflowType type;
00781       command->GetType(type);
00782       if (eReflowType_StyleChanged == type) {
00783         isStyleChanged = PR_TRUE;
00784       }
00785       else NS_ASSERTION(PR_FALSE, "table cell target of illegal incremental reflow type");
00786     }
00787     // else the reflow command will be passed down to the child
00788   }
00789 
00790   // Try to reflow the child into the available space. It might not
00791   // fit or might need continuing.
00792   if (availSize.height < 0)
00793     availSize.height = 1;
00794 
00795   nsHTMLReflowMetrics kidSize(NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth ||
00796                               aDesiredSize.mComputeMEW,
00797                               aDesiredSize.mFlags);
00798   kidSize.width=kidSize.height=kidSize.ascent=kidSize.descent=0;
00799   SetPriorAvailWidth(aReflowState.availableWidth);
00800   nsIFrame* firstKid = mFrames.FirstChild();
00801   NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
00802 
00803   nscoord computedPaginatedHeight = 0;
00804 
00805   if (aReflowState.mFlags.mSpecialHeightReflow || 
00806       (HadSpecialReflow() && (eReflowReason_Incremental == aReflowState.reason))) {
00807     ((nsHTMLReflowState&)aReflowState).mComputedHeight = mRect.height - topInset - bottomInset;
00808     DISPLAY_REFLOW_CHANGE();
00809   }
00810   else if (aPresContext->IsPaginated()) {
00811     computedPaginatedHeight = CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this, *tableFrame, topInset + bottomInset);
00812     if (computedPaginatedHeight > 0) {
00813       ((nsHTMLReflowState&)aReflowState).mComputedHeight = computedPaginatedHeight;
00814       DISPLAY_REFLOW_CHANGE();
00815     }
00816   }      
00817   else {
00818     SetHasPctOverHeight(PR_FALSE);
00819   }
00820 
00821   // If it was a style change targeted at us, then reflow the child with a style change reason
00822   nsReflowReason reason = aReflowState.reason;
00823   if (isStyleChanged) {
00824     reason = eReflowReason_StyleChange;
00825     // the following could be optimized with a fair amount of effort
00826     tableFrame->SetNeedStrategyInit(PR_TRUE);
00827   }
00828 
00829   nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid, availSize, reason);
00830   // mIPercentHeightObserver is for non table related frames inside cells in quirks mode
00831   kidReflowState.mPercentHeightObserver = (eCompatibility_NavQuirks == compatMode) ? (nsIPercentHeightObserver *)this : nsnull;
00832 
00833   // Assume the inner child will stay positioned exactly where it is. Later in
00834   // VerticallyAlignChild() we'll move it if it turns out to be wrong. This
00835   // avoids excessive movement and is more stable
00836   nsPoint kidOrigin;
00837   if (isStyleChanged || 
00838       (eReflowReason_Initial == aReflowState.reason) ||
00839       (eReflowReason_StyleChange == aReflowState.reason)) {
00840     kidOrigin.MoveTo(leftInset, topInset);
00841   } else {
00842     // handle percent padding-left which was 0 during initial reflow
00843     if (eStyleUnit_Percent == aReflowState.mStylePadding->mPadding.GetLeftUnit()) {
00844       nsRect kidRect = firstKid->GetRect();
00845       // only move in the x direction for the same reason as above
00846       kidOrigin.MoveTo(leftInset, kidRect.y);
00847       firstKid->SetPosition(nsPoint(leftInset, kidRect.y));
00848     }
00849     kidOrigin = firstKid->GetPosition();
00850   }
00851 
00852 #if defined DEBUG_TABLE_REFLOW_TIMING
00853   nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState);
00854 #endif
00855   nscoord priorBlockHeight = GetLastBlockHeight();
00856   ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
00857               kidOrigin.x, kidOrigin.y, 0, aStatus);
00858   SetLastBlockHeight(kidSize.height);
00859   if (isStyleChanged) {
00860     Invalidate(GetOverflowRect(), PR_FALSE);
00861   }
00862 
00863 #if defined DEBUG_TABLE_REFLOW_TIMING
00864   nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState, &kidSize, aStatus);
00865 #endif
00866 
00867 #ifdef NS_DEBUG
00868   DebugCheckChildSize(firstKid, kidSize, availSize, (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth));
00869 #endif
00870 
00871   // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode 
00872   // see testcase "emptyCells.html"
00873   if ((0 == kidSize.width) || (0 == kidSize.height)) { // XXX why was this &&
00874     SetContentEmpty(PR_TRUE);
00875     if (NS_UNCONSTRAINEDSIZE == kidReflowState.availableWidth &&
00876         GetStyleTableBorder()->mEmptyCells != NS_STYLE_TABLE_EMPTY_CELLS_SHOW) {
00877       // need to reduce the insets by border if the cell is empty
00878       leftInset   -= border.left;
00879       rightInset  -= border.right;
00880       topInset    -= border.top;
00881       bottomInset -= border.bottom;
00882     }
00883   }
00884   else {
00885     SetContentEmpty(PR_FALSE);
00886     if ((eReflowReason_Incremental == aReflowState.reason) && noBorderBeforeReflow) {
00887       // need to consider borders, since they were factored out above
00888       leftInset   += border.left;
00889       rightInset  += border.right;
00890       topInset    += border.top;
00891       bottomInset += border.bottom;
00892       kidOrigin.MoveTo(leftInset, topInset);
00893     }
00894   }
00895 
00896   const nsStylePosition* pos = GetStylePosition();
00897 
00898   // calculate the min cell width
00899   nscoord onePixel = NSIntPixelsToTwips(1, p2t);
00900   nscoord smallestMinWidth = 0;
00901   if (eCompatibility_NavQuirks == compatMode) {
00902     if ((pos->mWidth.GetUnit() != eStyleUnit_Coord)   &&
00903         (pos->mWidth.GetUnit() != eStyleUnit_Percent)) {
00904       if (PR_TRUE == GetContentEmpty()) {
00905         if (border.left > 0) 
00906           smallestMinWidth += onePixel;
00907         if (border.right > 0) 
00908           smallestMinWidth += onePixel;
00909       }
00910     }
00911   }
00912   PRInt32 colspan = tableFrame->GetEffectiveColSpan(*this);
00913   if (colspan > 1) {
00914     smallestMinWidth = PR_MAX(smallestMinWidth, colspan * onePixel);
00915     nscoord spacingX = tableFrame->GetCellSpacingX();
00916     nscoord spacingExtra = spacingX * (colspan - 1);
00917     smallestMinWidth += spacingExtra;
00918     if (aReflowState.mComputedPadding.left > 0) {
00919       smallestMinWidth -= onePixel;
00920     }
00921   }
00922  
00923   if ((0 == kidSize.width) && (NS_UNCONSTRAINEDSIZE != kidReflowState.availableWidth)) {
00924     // empty content has to be forced to the assigned width for resize or incremental reflow
00925     kidSize.width = kidReflowState.availableWidth;
00926   }
00927   if (0 == kidSize.height) {
00928     if ((pos->mHeight.GetUnit() != eStyleUnit_Coord) &&
00929         (pos->mHeight.GetUnit() != eStyleUnit_Percent)) {
00930       PRInt32 pixHeight = (eCompatibility_NavQuirks == compatMode) ? 1 : 0;
00931       kidSize.height = NSIntPixelsToTwips(pixHeight, p2t);
00932     }
00933   }
00934   // end 0 dimensioned cells
00935 
00936   kidSize.width = PR_MAX(kidSize.width, smallestMinWidth); 
00937   if (!tableFrame->IsAutoLayout()) {
00938     // a cell in a fixed layout table is constrained to the avail width
00939     // if we need to shorten the cell the previous non overflowing block
00940     // will get some overflow area
00941     if (kidSize.width > availSize.width) {
00942       kidSize.width = availSize.width;
00943       firstKid->FinishAndStoreOverflow(&kidSize);
00944     }
00945   }
00946   //if (eReflowReason_Resize == aReflowState.reason) {
00947   //  NS_ASSERTION(kidSize.width <= availSize.width, "child needed more space during resize reflow");
00948   //}
00949   // Place the child
00950   FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize,
00951                     kidOrigin.x, kidOrigin.y, 0);
00952     
00953   // first, compute the height which can be set w/o being restricted by aMaxSize.height
00954   nscoord cellHeight = kidSize.height;
00955 
00956   if (NS_UNCONSTRAINEDSIZE != cellHeight) {
00957     cellHeight += topInset + bottomInset;
00958     // work around block rounding errors, round down to ensure we don't exceed the avail height in
00959     nsPixelRound roundMethod = (NS_UNCONSTRAINEDSIZE == availHeight) ? eAlwaysRoundUp : eAlwaysRoundDown;
00960     cellHeight = nsTableFrame::RoundToPixel(cellHeight, p2t, roundMethod); 
00961   }
00962 
00963   // next determine the cell's width
00964   nscoord cellWidth = kidSize.width;      // at this point, we've factored in the cell's style attributes
00965 
00966   // factor in border and padding
00967   if (NS_UNCONSTRAINEDSIZE != cellWidth) {
00968     cellWidth += leftInset + rightInset;    
00969   }
00970   cellWidth = nsTableFrame::RoundToPixel(cellWidth, p2t); // work around block rounding errors
00971 
00972   // set the cell's desired size and max element size
00973   aDesiredSize.width   = cellWidth;
00974   aDesiredSize.height  = cellHeight;
00975   aDesiredSize.ascent  = topInset;
00976   aDesiredSize.descent = bottomInset;
00977 
00978   aDesiredSize.ascent  += kidSize.ascent;
00979   aDesiredSize.descent += kidSize.descent;
00980   
00981   // the overflow area will be computed when the child will be vertically aligned
00982 
00983   if (aDesiredSize.mComputeMEW) {
00984     aDesiredSize.mMaxElementWidth =
00985       PR_MAX(smallestMinWidth, kidSize.mMaxElementWidth);
00986     if (NS_UNCONSTRAINEDSIZE != aDesiredSize.mMaxElementWidth) {
00987       aDesiredSize.mMaxElementWidth = nsTableFrame::RoundToPixel(
00988                   aDesiredSize.mMaxElementWidth + leftInset + rightInset, p2t);
00989     }
00990   }
00991   if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
00992     aDesiredSize.mMaximumWidth = kidSize.mMaximumWidth;
00993     if (NS_UNCONSTRAINEDSIZE != aDesiredSize.mMaximumWidth) {
00994       aDesiredSize.mMaximumWidth += leftInset + rightInset;
00995       aDesiredSize.mMaximumWidth = nsTableFrame::RoundToPixel(aDesiredSize.mMaximumWidth, p2t);
00996     }
00997     // make sure the preferred width is at least as big as the max element width
00998     if (aDesiredSize.mComputeMEW) {
00999       aDesiredSize.mMaximumWidth = PR_MAX(aDesiredSize.mMaximumWidth, aDesiredSize.mMaxElementWidth);
01000     }
01001   }
01002 
01003   if (aReflowState.mFlags.mSpecialHeightReflow) {
01004     if (aDesiredSize.height > mRect.height) {
01005       // set a bit indicating that the pct height contents exceeded 
01006       // the height that they could honor in the pass 2 reflow
01007       SetHasPctOverHeight(PR_TRUE);
01008     }
01009     if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) {
01010       aDesiredSize.height = mRect.height;
01011     }
01012     SetNeedSpecialReflow(PR_FALSE);
01013     SetHadSpecialReflow(PR_TRUE);
01014   }
01015   else if (HadSpecialReflow()) {
01016     if (eReflowReason_Incremental == aReflowState.reason) {
01017       // with an unconstrained height, if the block height value hasn't changed, 
01018       // use the last height of the cell.
01019       if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && 
01020           (GetLastBlockHeight() == priorBlockHeight)) {
01021         aDesiredSize.height = mRect.height;
01022       }
01023     }
01024     // XXX should probably call SetHadSpecialReflow(PR_FALSE) when things change so that
01025     // nothing inside the cell has a percent height, but it is not easy determining this 
01026   }
01027 
01028   // remember the desired size for this reflow
01029   SetDesiredSize(aDesiredSize);
01030 
01031 #if defined DEBUG_TABLE_REFLOW_TIMING
01032   nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
01033 #endif
01034 
01035   if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
01036     SetNeedPass2Reflow(PR_TRUE);
01037   }
01038   else if ((eReflowReason_Initial == aReflowState.reason) || 
01039            (eReflowReason_Resize  == aReflowState.reason)) { 
01040     SetNeedPass2Reflow(PR_FALSE);
01041   }
01042 
01043   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
01044   return NS_OK;
01045 }
01046 
01047 /* ----- global methods ----- */
01048 
01049 NS_IMPL_ADDREF_INHERITED(nsTableCellFrame, nsHTMLContainerFrame)
01050 NS_IMPL_RELEASE_INHERITED(nsTableCellFrame, nsHTMLContainerFrame)
01051 
01052 nsresult nsTableCellFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
01053 {
01054   if (NULL == aInstancePtr) {
01055     return NS_ERROR_NULL_POINTER;
01056   }
01057 
01058   if (aIID.Equals(NS_GET_IID(nsITableCellLayout))) {
01059     *aInstancePtr = (void*) (nsITableCellLayout *)this;
01060     return NS_OK;
01061   }
01062   if (aIID.Equals(NS_GET_IID(nsIPercentHeightObserver))) {
01063     *aInstancePtr = (void*) (nsIPercentHeightObserver *)this;
01064     return NS_OK;
01065   }
01066 
01067   return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
01068 }
01069 
01070 #ifdef ACCESSIBILITY
01071 NS_IMETHODIMP nsTableCellFrame::GetAccessible(nsIAccessible** aAccessible)
01072 {
01073   nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
01074 
01075   if (accService) {
01076     return accService->CreateHTMLTableCellAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
01077   }
01078 
01079   return NS_ERROR_FAILURE;
01080 }
01081 #endif
01082 
01083 /* This is primarily for editor access via nsITableLayout */
01084 NS_IMETHODIMP
01085 nsTableCellFrame::GetCellIndexes(PRInt32 &aRowIndex, PRInt32 &aColIndex)
01086 {
01087   nsresult res = GetRowIndex(aRowIndex);
01088   if (NS_FAILED(res))
01089   {
01090     aColIndex = 0;
01091     return res;
01092   }
01093   aColIndex = mBits.mColIndex;
01094   return  NS_OK;
01095 }
01096 
01097 NS_IMETHODIMP
01098 nsTableCellFrame::GetPreviousCellInColumn(nsITableCellLayout **aCellLayout)
01099 {
01100   if (!aCellLayout) return NS_ERROR_NULL_POINTER;
01101   *aCellLayout = nsnull;
01102 
01103   nsTableFrame* tableFrame = nsnull; 
01104   nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
01105   if (NS_FAILED(rv)) return rv;
01106   if (!tableFrame) return NS_ERROR_FAILURE;
01107 
01108   // Get current cell location
01109   PRInt32 rowIndex, colIndex;
01110   GetCellIndexes(rowIndex, colIndex);
01111   if (colIndex > 0)
01112   {
01113     // Get the cellframe at previous colIndex
01114     nsTableCellFrame *cellFrame = tableFrame->GetCellFrameAt(rowIndex, colIndex-1);
01115     if (!cellFrame) return NS_ERROR_FAILURE;
01116     return CallQueryInterface(cellFrame, aCellLayout);
01117   }
01118   return NS_ERROR_FAILURE;
01119 }
01120 
01121 NS_IMETHODIMP
01122 nsTableCellFrame::GetNextCellInColumn(nsITableCellLayout **aCellLayout)
01123 {
01124   if (!aCellLayout) return NS_ERROR_NULL_POINTER;
01125   *aCellLayout = nsnull;
01126 
01127   nsTableFrame* tableFrame = nsnull; 
01128   nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
01129   if (NS_FAILED(rv)) return rv;
01130   if (!tableFrame) return NS_ERROR_FAILURE;
01131 
01132   // Get current cell location
01133   PRInt32 rowIndex, colIndex;
01134   GetCellIndexes(rowIndex, colIndex);
01135 
01136   // Get the cellframe at next colIndex
01137   nsTableCellFrame *cellFrame = tableFrame->GetCellFrameAt(rowIndex, colIndex+1);
01138   if (!cellFrame) return NS_ERROR_FAILURE;
01139   return CallQueryInterface(cellFrame, aCellLayout);
01140 }
01141 
01142 nsresult 
01143 NS_NewTableCellFrame(nsIPresShell* aPresShell, 
01144                      PRBool        aIsBorderCollapse,
01145                      nsIFrame**    aNewFrame)
01146 {
01147   NS_PRECONDITION(aNewFrame, "null OUT ptr");
01148   if (nsnull == aNewFrame) {
01149     return NS_ERROR_NULL_POINTER;
01150   }
01151   nsTableCellFrame* it = (aIsBorderCollapse) ? new (aPresShell) nsBCTableCellFrame 
01152                                              : new (aPresShell) nsTableCellFrame;
01153   if (nsnull == it) {
01154     return NS_ERROR_OUT_OF_MEMORY;
01155   }
01156   *aNewFrame = it;
01157   return NS_OK;
01158 }
01159 
01160 nsMargin* 
01161 nsTableCellFrame::GetBorderWidth(float      aPixelsToTwips,
01162                                  nsMargin&  aBorder) const
01163 {
01164   aBorder = GetStyleBorder()->GetBorder();
01165   return &aBorder;
01166 }
01167 
01168 nsIAtom*
01169 nsTableCellFrame::GetType() const
01170 {
01171   return nsLayoutAtoms::tableCellFrame;
01172 }
01173 
01174 #ifdef DEBUG
01175 NS_IMETHODIMP
01176 nsTableCellFrame::GetFrameName(nsAString& aResult) const
01177 {
01178   return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult);
01179 }
01180 #endif
01181 
01182 void nsTableCellFrame::SetCollapseOffsetX(nscoord aXOffset)
01183 {
01184   // Get the frame property (creating a point struct if necessary)
01185   nsPoint* offset = (nsPoint*)nsTableFrame::GetProperty(this, nsLayoutAtoms::collapseOffsetProperty, aXOffset != 0);
01186 
01187   if (offset) {
01188     offset->x = aXOffset;
01189   }
01190 }
01191 
01192 void nsTableCellFrame::SetCollapseOffsetY(nscoord aYOffset)
01193 {
01194   // Get the property (creating a point struct if necessary)
01195   nsPoint* offset = (nsPoint*)nsTableFrame::GetProperty(this, nsLayoutAtoms::collapseOffsetProperty, aYOffset != 0);
01196 
01197   if (offset) {
01198     offset->y = aYOffset;
01199   }
01200 }
01201 
01202 void nsTableCellFrame::GetCollapseOffset(nsPoint& aOffset)
01203 {
01204   // See if the property is set
01205   nsPoint* offset = (nsPoint*)nsTableFrame::GetProperty(this, nsLayoutAtoms::collapseOffsetProperty);
01206 
01207   if (offset) {
01208     aOffset = *offset;
01209   } else {
01210     aOffset.MoveTo(0, 0);
01211   }
01212 }
01213 
01214 // nsBCTableCellFrame
01215 
01216 nsBCTableCellFrame::nsBCTableCellFrame()
01217 :nsTableCellFrame()
01218 {
01219   mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
01220 }
01221 
01222 nsBCTableCellFrame::~nsBCTableCellFrame()
01223 {
01224 }
01225 
01226 nsIAtom*
01227 nsBCTableCellFrame::GetType() const
01228 {
01229   return nsLayoutAtoms::bcTableCellFrame;
01230 }
01231 
01232 #ifdef DEBUG
01233 NS_IMETHODIMP
01234 nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
01235 {
01236   return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
01237 }
01238 #endif
01239 
01240 nsMargin* 
01241 nsBCTableCellFrame::GetBorderWidth(float      aPixelsToTwips,
01242                                    nsMargin&  aBorder) const
01243 {
01244   aBorder.top    = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopBorder);
01245   aBorder.right  = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, mRightBorder);
01246   aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomBorder);
01247   aBorder.left   = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mLeftBorder);
01248   return &aBorder;
01249 }
01250 
01251 BCPixelSize
01252 nsBCTableCellFrame::GetBorderWidth(PRUint8 aSide) const
01253 {
01254   switch(aSide) {
01255   case NS_SIDE_TOP:
01256     return BC_BORDER_BOTTOM_HALF(mTopBorder);
01257   case NS_SIDE_RIGHT:
01258     return BC_BORDER_LEFT_HALF(mRightBorder);
01259   case NS_SIDE_BOTTOM:
01260     return BC_BORDER_TOP_HALF(mBottomBorder);
01261   default:
01262     return BC_BORDER_RIGHT_HALF(mLeftBorder);
01263   }
01264 }
01265 
01266 void 
01267 nsBCTableCellFrame::SetBorderWidth(PRUint8 aSide,
01268                                    BCPixelSize aValue)
01269 {
01270   switch(aSide) {
01271   case NS_SIDE_TOP:
01272     mTopBorder = aValue;
01273     break;
01274   case NS_SIDE_RIGHT:
01275     mRightBorder = aValue;
01276     break;
01277   case NS_SIDE_BOTTOM:
01278     mBottomBorder = aValue;
01279     break;
01280   default:
01281     mLeftBorder = aValue;
01282   }
01283 }
01284 
01285 /* virtual */ void
01286 nsBCTableCellFrame::GetSelfOverflow(nsRect& aOverflowArea)
01287 {
01288   nsMargin halfBorder;
01289   float p2t = GetPresContext()->PixelsToTwips();
01290   halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder);
01291   halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder);
01292   halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder);
01293   halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder);
01294 
01295   nsRect overflow(nsPoint(0,0), GetSize());
01296   overflow.Inflate(halfBorder);
01297   aOverflowArea = overflow;
01298 }
01299 
01300 
01301 void
01302 nsBCTableCellFrame::PaintUnderlay(nsPresContext&           aPresContext,
01303                                   nsIRenderingContext&      aRenderingContext,
01304                                   const nsRect&             aDirtyRect,
01305                                   PRUint32&                 aFlags,
01306                                   const nsStyleBorder&      aStyleBorder,
01307                                   const nsStylePadding&     aStylePadding,
01308                                   const nsStyleTableBorder& aCellTableStyle)
01309 {
01310   if (!(aFlags & NS_PAINT_FLAG_TABLE_BG_PAINT)
01311       /*direct call; not table-based paint*/ ||
01312       (aFlags & NS_PAINT_FLAG_TABLE_CELL_BG_PASS)
01313       /*table cell background only pass*/) {
01314     // make border-width reflect the half of the border-collapse
01315     // assigned border that's inside the cell
01316     GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
01317     nsMargin borderWidth;
01318     GetBorderWidth(p2t, borderWidth);
01319 
01320     nsStyleBorder myBorder(aStyleBorder);
01321 
01322     NS_FOR_CSS_SIDES(side) {
01323       myBorder.SetBorderWidth(side, borderWidth.side(side));
01324     }
01325 
01326     nsRect rect(0, 0, mRect.width, mRect.height);
01327     nsCSSRendering::PaintBackground(&aPresContext, aRenderingContext, this,
01328                                     aDirtyRect, rect, myBorder, aStylePadding,
01329                                     PR_TRUE);
01330     // borders are painted by nsTableFrame
01331   }
01332 }