Back to index

lightning-sunbird  0.9+nobinonly
nsBox.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 Communicator client 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  *   Author: Eric D Vaughan <evaughan@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsBoxLayoutState.h"
00041 #include "nsBox.h"
00042 #include "nsBoxFrame.h"
00043 #include "nsPresContext.h"
00044 #include "nsCOMPtr.h"
00045 #include "nsIContent.h"
00046 #include "nsIViewManager.h"
00047 #include "nsIView.h"
00048 #include "nsIPresShell.h"
00049 #include "nsHTMLContainerFrame.h"
00050 #include "nsINameSpaceManager.h"
00051 #include "nsHTMLAtoms.h"
00052 #include "nsFrameManager.h"
00053 #include "nsLayoutAtoms.h"
00054 #include "nsXULAtoms.h"
00055 #include "nsIDOMNode.h"
00056 #include "nsIDOMNamedNodeMap.h"
00057 #include "nsIDOMAttr.h"
00058 #include "nsIWidget.h"
00059 #include "nsIRenderingContext.h"
00060 #include "nsIDocument.h"
00061 #include "nsIDeviceContext.h"
00062 #include "nsITheme.h"
00063 #include "nsIServiceManager.h"
00064 #include "nsIBoxLayout.h"
00065 
00066 #ifdef DEBUG_COELESCED
00067 static PRInt32 coelesced = 0;
00068 #endif
00069 
00070 #ifdef DEBUG_LAYOUT
00071 PRInt32 gIndent = 0;
00072 #endif
00073 
00074 #ifdef DEBUG_LAYOUT
00075 void
00076 nsBoxAddIndents()
00077 {
00078     for(PRInt32 i=0; i < gIndent; i++)
00079     {
00080         printf(" ");
00081     }
00082 }
00083 #endif
00084 
00085 #ifdef DEBUG_LAYOUT
00086 void
00087 nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult)
00088 {
00089    aResult.Append(aAttribute);
00090    aResult.AppendLiteral("='");
00091    aResult.Append(aValue);
00092    aResult.AppendLiteral("' ");
00093 }
00094 
00095 void
00096 nsBox::ListBox(nsAutoString& aResult)
00097 {
00098     nsAutoString name;
00099     GetBoxName(name);
00100 
00101     char addr[100];
00102     sprintf(addr, "[@%p] ", NS_STATIC_CAST(void*, this));
00103 
00104     aResult.AppendASCII(addr);
00105     aResult.Append(name);
00106     aResult.AppendLiteral(" ");
00107 
00108     nsIContent* content = GetContent();
00109 
00110     // add on all the set attributes
00111     if (content) {
00112       nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
00113       nsCOMPtr<nsIDOMNamedNodeMap> namedMap;
00114 
00115       node->GetAttributes(getter_AddRefs(namedMap));
00116       PRUint32 length;
00117       namedMap->GetLength(&length);
00118 
00119       nsCOMPtr<nsIDOMNode> attribute;
00120       for (PRUint32 i = 0; i < length; ++i)
00121       {
00122         namedMap->Item(i, getter_AddRefs(attribute));
00123         nsCOMPtr<nsIDOMAttr> attr(do_QueryInterface(attribute));
00124         attr->GetName(name);
00125         nsAutoString value;
00126         attr->GetValue(value);
00127         AppendAttribute(name, value, aResult);
00128       }
00129     }
00130 }
00131 
00132 NS_IMETHODIMP
00133 nsBox::DumpBox(FILE* aFile)
00134 {
00135   nsAutoString s;
00136   ListBox(s);
00137   fprintf(aFile, "%s", NS_LossyConvertUCS2toASCII(s).get());
00138   return NS_OK;
00139 }
00140 
00141 void
00142 nsBox::PropagateDebug(nsBoxLayoutState& aState)
00143 {
00144   // propagate debug information
00145   if (mState & NS_STATE_DEBUG_WAS_SET) {
00146     if (mState & NS_STATE_SET_TO_DEBUG)
00147       SetDebug(aState, PR_TRUE);
00148     else
00149       SetDebug(aState, PR_FALSE);
00150   } else if (mState & NS_STATE_IS_ROOT) {
00151     SetDebug(aState, gDebug);
00152   }
00153 }
00154 #endif
00155 
00159 NS_IMETHODIMP 
00160 nsBox::ChildrenMustHaveWidgets(PRBool& aMust) const
00161 {
00162   aMust = PR_FALSE;
00163   return NS_OK;
00164 }
00165 
00166 #ifdef DEBUG_LAYOUT
00167 void
00168 nsBox::GetBoxName(nsAutoString& aName)
00169 {
00170   aName.AssignLiteral("Box");
00171 }
00172 #endif
00173 
00174 nsresult
00175 nsBox::BeginLayout(nsBoxLayoutState& aState)
00176 {
00177 #ifdef DEBUG_LAYOUT 
00178 
00179   nsBoxAddIndents();
00180 
00181   nsAutoString reason;
00182   switch(aState.LayoutReason())
00183     {
00184     case nsBoxLayoutState::Dirty:
00185       reason.AssignLiteral("Dirty");
00186       break;
00187     case nsBoxLayoutState::Initial:
00188       reason.AssignLiteral("Initial");
00189       break;
00190     case nsBoxLayoutState::Resize:
00191       reason.AssignLiteral("Resize");
00192       break;
00193     }
00194 
00195   char ch[100];
00196   reason.ToCString(ch,100);
00197   printf("%s Layout: ", ch);
00198   DumpBox(stdout);
00199   printf("\n");
00200   gIndent++;
00201 #endif
00202 
00203   // mark ourselves as dirty so no child under us
00204   // can post an incremental layout.
00205   mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
00206 
00207 #ifdef DEBUG_LAYOUT
00208   PropagateDebug(aState);
00209 #endif
00210 
00211   return NS_OK;
00212 }
00213 
00214 NS_IMETHODIMP
00215 nsBox::DoLayout(nsBoxLayoutState& aState)
00216 {
00217   return NS_OK;
00218 }
00219 
00220 nsresult
00221 nsBox::EndLayout(nsBoxLayoutState& aState)
00222 {
00223 
00224   #ifdef DEBUG_LAYOUT
00225       --gIndent;
00226   #endif
00227 
00228   return SyncLayout(aState);
00229 }
00230 
00231 #ifdef REFLOW_COELESCED
00232 void Coelesced()
00233 {
00234    printf("Coelesed=%d\n", ++coelesced);
00235 
00236 }
00237 
00238 #endif
00239 
00240 PRBool nsBox::gGotTheme = PR_FALSE;
00241 nsITheme* nsBox::gTheme = nsnull;
00242 
00243 MOZ_DECL_CTOR_COUNTER(nsBox)
00244 
00245 nsBox::nsBox()
00246 {
00247   MOZ_COUNT_CTOR(nsBox);
00248   //mX = 0;
00249   //mY = 0;
00250   if (!gGotTheme) {
00251     gGotTheme = PR_TRUE;
00252     CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme);
00253   }
00254 }
00255 
00256 nsBox::~nsBox()
00257 {
00258   // NOTE:  This currently doesn't get called for |nsBoxToBlockAdaptor|
00259   // objects, so don't rely on putting anything here.
00260   MOZ_COUNT_DTOR(nsBox);
00261 }
00262 
00263 /* static */ void
00264 nsBox::Shutdown()
00265 {
00266   gGotTheme = PR_FALSE;
00267   NS_IF_RELEASE(gTheme);
00268 }
00269 
00270 NS_IMETHODIMP
00271 nsBox::MarkDirty(nsBoxLayoutState& aState)
00272 {
00273   // only reflow if we aren't already dirty.
00274   if (GetStateBits() & NS_FRAME_IS_DIRTY) {      
00275 #ifdef DEBUG_COELESCED
00276       Coelesced();
00277 #endif
00278       return NS_OK;
00279   }
00280 
00281   AddStateBits(NS_FRAME_IS_DIRTY);
00282 
00283   NeedsRecalc();
00284 
00285   nsCOMPtr<nsIBoxLayout> layout;
00286   GetLayoutManager(getter_AddRefs(layout));
00287   if (layout)
00288     layout->BecameDirty(this, aState);
00289 
00290   if (GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) {   
00291 #ifdef DEBUG_COELESCED
00292       Coelesced();
00293 #endif
00294       return NS_OK;
00295   }
00296 
00297   nsIBox* parent = nsnull;
00298   GetParentBox(&parent);
00299   if (parent)
00300      return parent->RelayoutDirtyChild(aState, this);
00301   else {
00302     return GetParent()->ReflowDirtyChild(aState.PresShell(), this);
00303   }
00304 }
00305 
00306 nsresult
00307 nsIFrame::MarkDirtyChildren(nsBoxLayoutState& aState)
00308 {
00309   return RelayoutDirtyChild(aState, nsnull);
00310 }
00311 
00312 NS_IMETHODIMP
00313 nsBox::MarkStyleChange(nsBoxLayoutState& aState)
00314 {
00315   NeedsRecalc();
00316 
00317   if (HasStyleChange())
00318     return NS_OK;
00319 
00320   // iterate through all children making them dirty
00321   MarkChildrenStyleChange();
00322 
00323   nsCOMPtr<nsIBoxLayout> layout;
00324   GetLayoutManager(getter_AddRefs(layout));
00325   if (layout)
00326     layout->BecameDirty(this, aState);
00327 
00328   nsIBox* parent = nsnull;
00329   GetParentBox(&parent);
00330   if (parent)
00331      return parent->RelayoutDirtyChild(aState, this);
00332   else {
00333     /*
00334     aState.PresShell()->AppendReflowCommand(this, eReflowType_StyleChanged,
00335                                             nsnull);
00336     return NS_OK;
00337     */
00338     return GetParent()->ReflowDirtyChild(aState.PresShell(), this);
00339   }
00340 
00341   return NS_OK;
00342 }
00343 
00344 PRBool
00345 nsBox::HasStyleChange()
00346 {
00347   PRBool aDirty = PR_FALSE;
00348   IsDirty(aDirty);
00349   return aDirty;
00350 }
00351 
00352 void
00353 nsBox::SetStyleChangeFlag(PRBool aDirty)
00354 {
00355   NeedsRecalc();
00356   AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
00357 }
00358 
00359 NS_IMETHODIMP
00360 nsBox::MarkChildrenStyleChange()
00361 {
00362   // only reflow if we aren't already dirty.
00363   if (HasStyleChange()) {   
00364 #ifdef DEBUG_COELESCED
00365     printf("StyleChange reflows coelesced=%d\n", ++StyleCoelesced);  
00366 #endif
00367     return NS_OK;
00368   }
00369 
00370   SetStyleChangeFlag(PR_TRUE);
00371 
00372   nsIBox* child = nsnull;
00373   GetChildBox(&child);
00374   while(child)
00375   {
00376     child->MarkChildrenStyleChange();
00377     child->GetNextBox(&child);
00378   }
00379 
00380   return NS_OK;
00381 }
00382 
00383 NS_IMETHODIMP
00384 nsBox::RelayoutDirtyChild(nsBoxLayoutState& aState, nsIBox* aChild)
00385 {
00386     if (aChild != nsnull) {
00387         nsCOMPtr<nsIBoxLayout> layout;
00388         GetLayoutManager(getter_AddRefs(layout));
00389         if (layout)
00390           layout->ChildBecameDirty(this, aState, aChild);
00391     }
00392 
00393     // if we are not dirty mark ourselves dirty and tell our parent we are dirty too.
00394     if (!(GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) {      
00395       // Mark yourself as dirty and needing to be recalculated
00396       AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
00397 
00398       if (GetStateBits() & NS_FRAME_REFLOW_ROOT) {
00399         aState.PresShell()->AppendReflowCommand(this, eReflowType_ReflowDirty,
00400                                                 nsnull);
00401         return NS_OK;
00402       }
00403 
00404       NeedsRecalc();
00405 
00406       nsIBox* parentBox = nsnull;
00407       GetParentBox(&parentBox);
00408       if (parentBox)
00409          return parentBox->RelayoutDirtyChild(aState, this);
00410       return GetParent()->ReflowDirtyChild(aState.PresShell(), this);
00411     } else {
00412 #ifdef DEBUG_COELESCED
00413       Coelesced();
00414 #endif
00415     }
00416 
00417     return NS_OK;
00418 }
00419 
00420 NS_IMETHODIMP
00421 nsBox::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIBox* aChild)
00422 {
00423   return NS_OK;
00424 }
00425 
00426 NS_IMETHODIMP
00427 nsBox::GetVAlign(Valignment& aAlign)
00428 {
00429   aAlign = vAlign_Top;
00430    return NS_OK;
00431 }
00432 
00433 NS_IMETHODIMP
00434 nsBox::GetHAlign(Halignment& aAlign)
00435 {
00436   aAlign = hAlign_Left;
00437    return NS_OK;
00438 }
00439 
00440 nsresult
00441 nsIFrame::GetClientRect(nsRect& aClientRect)
00442 {
00443   GetContentRect(aClientRect);
00444 
00445   nsMargin borderPadding;
00446   GetBorderAndPadding(borderPadding);
00447 
00448   aClientRect.Deflate(borderPadding);
00449 
00450   nsMargin insets;
00451   GetInset(insets);
00452 
00453   aClientRect.Deflate(insets);
00454   if (aClientRect.width < 0)
00455      aClientRect.width = 0;
00456 
00457   if (aClientRect.height < 0)
00458      aClientRect.height = 0;
00459 
00460  // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0");
00461 
00462   return NS_OK;
00463 }
00464 
00465 nsresult
00466 nsIFrame::GetContentRect(nsRect& aContentRect)
00467 {
00468   aContentRect = mRect;
00469   aContentRect.x = 0;
00470   aContentRect.y = 0;
00471   NS_BOX_ASSERTION(this, aContentRect.width >=0 && aContentRect.height >= 0, "Content Size < 0");
00472   return NS_OK;
00473 }
00474 
00475 NS_IMETHODIMP
00476 nsBox::SetBounds(nsBoxLayoutState& aState, const nsRect& aRect, PRBool aRemoveOverflowArea)
00477 {
00478     NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetBounds Size < 0");
00479 
00480     nsRect rect(mRect);
00481 
00482     PRUint32 flags = 0;
00483     GetLayoutFlags(flags);
00484 
00485     PRUint32 stateFlags = aState.LayoutFlags();
00486 
00487     flags |= stateFlags;
00488 
00489     if (flags & NS_FRAME_NO_MOVE_FRAME)
00490       SetSize(nsSize(aRect.width, aRect.height));
00491     else
00492       SetRect(aRect);
00493 
00494     // Nuke the overflow area. The caller is responsible for restoring
00495     // it if necessary.
00496     if (aRemoveOverflowArea && (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN)) {
00497       // remove the previously stored overflow area
00498       GetPresContext()->PropertyTable()->
00499         DeleteProperty(this, nsLayoutAtoms::overflowAreaProperty);
00500       RemoveStateBits(NS_FRAME_OUTSIDE_CHILDREN);
00501     }
00502 
00503     if (!(flags & NS_FRAME_NO_MOVE_VIEW))
00504     {
00505       nsContainerFrame::PositionFrameView(this);
00506       if ((rect.x != aRect.x) || (rect.y != aRect.y))
00507         nsContainerFrame::PositionChildViews(this);
00508     }
00509   
00510 
00511    /*  
00512     // only if the origin changed
00513     if ((rect.x != aRect.x) || (rect.y != aRect.y))  {
00514       if (frame->HasView()) {
00515         nsContainerFrame::PositionFrameView(presContext, frame,
00516                                             frame->GetView());
00517       } else {
00518         nsContainerFrame::PositionChildViews(presContext, frame);
00519       }
00520     }
00521     */
00522     
00523 
00524     return NS_OK;
00525 }
00526 
00527 void
00528 nsBox::GetLayoutFlags(PRUint32& aFlags)
00529 {
00530   aFlags = 0;
00531 }
00532 
00533 
00534 NS_IMETHODIMP
00535 nsIFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding)
00536 {
00537   aBorderAndPadding.SizeTo(0, 0, 0, 0);
00538   nsresult rv = GetBorder(aBorderAndPadding);
00539   if (NS_FAILED(rv))
00540     return rv;
00541 
00542   nsMargin padding;
00543   rv = GetPadding(padding);
00544   if (NS_FAILED(rv))
00545     return rv;
00546 
00547   aBorderAndPadding += padding;
00548 
00549   return rv;
00550 }
00551 
00552 NS_IMETHODIMP
00553 nsBox::GetBorder(nsMargin& aMargin)
00554 {
00555   aMargin.SizeTo(0,0,0,0);
00556     
00557   const nsStyleDisplay* disp = GetStyleDisplay();
00558   if (disp->mAppearance && gTheme) {
00559     // Go to the theme for the border.
00560     nsPresContext *context = GetPresContext();
00561     if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
00562       nsMargin margin(0, 0, 0, 0);
00563       gTheme->GetWidgetBorder(context->DeviceContext(), this,
00564                               disp->mAppearance, &margin);
00565       float p2t = context->ScaledPixelsToTwips();
00566       aMargin.top = NSIntPixelsToTwips(margin.top, p2t);
00567       aMargin.right = NSIntPixelsToTwips(margin.right, p2t);
00568       aMargin.bottom = NSIntPixelsToTwips(margin.bottom, p2t);
00569       aMargin.left = NSIntPixelsToTwips(margin.left, p2t);
00570       return NS_OK;
00571     }
00572   }
00573 
00574   aMargin = GetStyleBorder()->GetBorder();
00575 
00576   return NS_OK;
00577 }
00578 
00579 NS_IMETHODIMP
00580 nsBox::GetPadding(nsMargin& aMargin)
00581 {
00582   const nsStyleDisplay *disp = GetStyleDisplay();
00583   if (disp->mAppearance && gTheme) {
00584     // Go to the theme for the padding.
00585     nsPresContext *context = GetPresContext();
00586     if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
00587       nsMargin margin(0, 0, 0, 0);
00588       PRBool useThemePadding;
00589 
00590       useThemePadding = gTheme->GetWidgetPadding(context->DeviceContext(),
00591                                                  this, disp->mAppearance,
00592                                                  &margin);
00593       if (useThemePadding) {
00594         float p2t = context->ScaledPixelsToTwips();
00595         aMargin.top = NSIntPixelsToTwips(margin.top, p2t);
00596         aMargin.right = NSIntPixelsToTwips(margin.right, p2t);
00597         aMargin.bottom = NSIntPixelsToTwips(margin.bottom, p2t);
00598         aMargin.left = NSIntPixelsToTwips(margin.left, p2t);
00599         return NS_OK;
00600       }
00601     }
00602   }
00603 
00604   aMargin.SizeTo(0,0,0,0);
00605   GetStylePadding()->GetPadding(aMargin);
00606 
00607   return NS_OK;
00608 }
00609 
00610 NS_IMETHODIMP
00611 nsBox::GetMargin(nsMargin& aMargin)
00612 {
00613   aMargin.SizeTo(0,0,0,0);
00614   GetStyleMargin()->GetMargin(aMargin);
00615 
00616   return NS_OK;
00617 }
00618 
00619 nsresult
00620 nsIFrame::GetParentBox(nsIBox** aParent)
00621 {
00622   *aParent = (mParent && mParent->IsBoxFrame()) ? mParent : nsnull;
00623   return NS_OK;
00624 }
00625 
00626 NS_IMETHODIMP
00627 nsBox::NeedsRecalc()
00628 {
00629   return NS_OK;
00630 }
00631 
00632 void
00633 nsBox::SizeNeedsRecalc(nsSize& aSize)
00634 {
00635   aSize.width  = -1;
00636   aSize.height = -1;
00637 }
00638 
00639 void
00640 nsBox::CoordNeedsRecalc(PRInt32& aFlex)
00641 {
00642   aFlex = -1;
00643 }
00644 
00645 PRBool
00646 nsBox::DoesNeedRecalc(const nsSize& aSize)
00647 {
00648   return (aSize.width == -1 || aSize.height == -1);
00649 }
00650 
00651 PRBool
00652 nsBox::DoesNeedRecalc(nscoord aCoord)
00653 {
00654   return (aCoord == -1);
00655 }
00656 
00657 PRBool
00658 nsBox::GetWasCollapsed(nsBoxLayoutState& aState)
00659 {
00660   return (GetStateBits() & NS_STATE_IS_COLLAPSED) != 0;
00661 }
00662 
00663 void
00664 nsBox::SetWasCollapsed(nsBoxLayoutState& aState, PRBool aCollapsed)
00665 {
00666   if (aCollapsed)
00667      AddStateBits(NS_STATE_IS_COLLAPSED);
00668   else
00669      RemoveStateBits(NS_STATE_IS_COLLAPSED);
00670 }
00671 
00672 NS_IMETHODIMP
00673 nsBox::SetLayoutManager(nsIBoxLayout* aLayout)
00674 {
00675   return NS_OK;
00676 }
00677 
00678 NS_IMETHODIMP
00679 nsBox::GetLayoutManager(nsIBoxLayout** aLayout)
00680 {
00681   *aLayout = nsnull;
00682   return NS_OK;
00683 }
00684 
00685 
00686 NS_IMETHODIMP
00687 nsBox::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
00688 {
00689   aSize.width = 0;
00690   aSize.height = 0;
00691 
00692   PRBool collapsed = PR_FALSE;
00693   IsCollapsed(aState, collapsed);
00694   if (collapsed)
00695     return NS_OK;
00696 
00697   AddBorderAndPadding(aSize);
00698   AddInset(aSize);
00699   nsIBox::AddCSSPrefSize(aState, this, aSize);
00700 
00701   nsSize minSize(0, 0), maxSize(0, 0);
00702   GetMinSize(aState, minSize);
00703   GetMaxSize(aState, maxSize);
00704 
00705   BoundsCheck(minSize, aSize, maxSize);
00706 
00707   return NS_OK;
00708 }
00709 
00710 NS_IMETHODIMP
00711 nsBox::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize)
00712 {
00713   aSize.width = 0;
00714   aSize.height = 0;
00715 
00716   PRBool collapsed = PR_FALSE;
00717   IsCollapsed(aState, collapsed);
00718   if (collapsed)
00719     return NS_OK;
00720 
00721   AddBorderAndPadding(aSize);
00722   AddInset(aSize);
00723   nsIBox::AddCSSMinSize(aState, this, aSize);
00724   return NS_OK;
00725 }
00726 
00727 nsSize
00728 nsBox::GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState)
00729 {
00730   return nsSize(0, 0);
00731 }
00732 
00733 NS_IMETHODIMP
00734 nsBox::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize)
00735 {
00736   aSize.width = NS_INTRINSICSIZE;
00737   aSize.height = NS_INTRINSICSIZE;
00738 
00739   PRBool collapsed = PR_FALSE;
00740   IsCollapsed(aState, collapsed);
00741   if (collapsed)
00742     return NS_OK;
00743 
00744   AddBorderAndPadding(aSize);
00745   AddInset(aSize);
00746   nsIBox::AddCSSMaxSize(aState, this, aSize);
00747   return NS_OK;
00748 }
00749 
00750 NS_IMETHODIMP
00751 nsBox::GetFlex(nsBoxLayoutState& aState, nscoord& aFlex)
00752 {
00753   aFlex = 0;
00754 
00755   GetDefaultFlex(aFlex);
00756   nsIBox::AddCSSFlex(aState, this, aFlex);
00757 
00758   return NS_OK;
00759 }
00760 
00761 nsresult
00762 nsIFrame::GetOrdinal(nsBoxLayoutState& aState, PRUint32& aOrdinal)
00763 {
00764   aOrdinal = DEFAULT_ORDINAL_GROUP;
00765   nsIBox::AddCSSOrdinal(aState, this, aOrdinal);
00766 
00767   return NS_OK;
00768 }
00769 
00770 NS_IMETHODIMP
00771 nsBox::GetAscent(nsBoxLayoutState& aState, nscoord& aAscent)
00772 {
00773   aAscent = 0;
00774   PRBool collapsed = PR_FALSE;
00775   IsCollapsed(aState, collapsed);
00776   if (collapsed)
00777     return NS_OK;
00778 
00779   nsSize size(0,0);
00780   nsresult rv = GetPrefSize(aState, size);
00781   aAscent = size.height;
00782   return rv;
00783 }
00784 
00785 NS_IMETHODIMP
00786 nsBox::IsCollapsed(nsBoxLayoutState& aState, PRBool& aCollapsed)
00787 {
00788   aCollapsed = PR_FALSE;
00789   nsIBox::AddCSSCollapsed(aState, this, aCollapsed);
00790 
00791   return NS_OK;
00792 }
00793 
00794 nsresult
00795 nsIFrame::Layout(nsBoxLayoutState& aState)
00796 {
00797   nsBox *box = NS_STATIC_CAST(nsBox*, this);
00798   box->BeginLayout(aState);
00799 
00800   box->DoLayout(aState);
00801 
00802   box->EndLayout(aState);
00803 
00804   return NS_OK;
00805 }
00806 
00807 PRBool
00808 nsBox::DoesClipChildren()
00809 {
00810   const nsStyleDisplay* display = GetStyleDisplay();
00811   NS_ASSERTION((display->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
00812                (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
00813                "If one overflow is clip, the other should be too");
00814   return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP;
00815 }
00816 
00817 nsresult
00818 nsBox::SyncLayout(nsBoxLayoutState& aState)
00819 {
00820   /*
00821   PRBool collapsed = PR_FALSE;
00822   IsCollapsed(aState, collapsed);
00823   if (collapsed) {
00824     CollapseChild(aState, this, PR_TRUE);
00825     return NS_OK;
00826   }
00827   */
00828   
00829 
00830   PRBool dirty = PR_FALSE;
00831   IsDirty(dirty);
00832   if (dirty || aState.LayoutReason() == nsBoxLayoutState::Initial)
00833      Redraw(aState);
00834 
00835   RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY
00836                   | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW);
00837 
00838   nsPresContext* presContext = aState.PresContext();
00839 
00840   PRUint32 flags = 0;
00841   GetLayoutFlags(flags);
00842 
00843   PRUint32 stateFlags = aState.LayoutFlags();
00844 
00845   flags |= stateFlags;
00846 
00847   nsRect rect(nsPoint(0, 0), GetSize());
00848 
00849   if (ComputesOwnOverflowArea()) {
00850     nsRect* overflow = GetOverflowAreaProperty();
00851     if (overflow)
00852       rect = *overflow;
00853 
00854   } else {
00855     if (!DoesClipChildren()) {
00856       // See if our child frames caused us to overflow after being laid
00857       // out. If so, store the overflow area.  This normally can't happen
00858       // in XUL, but it can happen with the CSS 'outline' property and
00859       // possibly with other exotic stuff (e.g. relatively positioned
00860       // frames in HTML inside XUL).
00861       nsIFrame* box;
00862       GetChildBox(&box);
00863       while (box) {
00864         nsRect* overflowArea = box->GetOverflowAreaProperty();
00865         nsRect bounds = overflowArea ? *overflowArea + box->GetPosition() :
00866                                          bounds = box->GetRect();
00867         rect.UnionRect(rect, bounds);
00868 
00869         box->GetNextBox(&box);
00870       }
00871     }
00872 
00873     const nsStyleDisplay* disp = GetStyleDisplay();
00874     if (disp->mAppearance && gTheme) {
00875       // Add in the theme's desired overflow
00876       if (gTheme->ThemeSupportsWidget(presContext, this, disp->mAppearance)) {
00877         nsRect r;
00878         if (gTheme->GetWidgetOverflow(presContext->DeviceContext(), this,
00879                                       disp->mAppearance, &r)) {
00880           rect.UnionRect(rect, r);
00881         }
00882       }
00883     }
00884 
00885     FinishAndStoreOverflow(&rect, GetSize());
00886   }
00887 
00888   nsIView* view = GetView();
00889   if (view) {
00890     // Make sure the frame's view is properly sized and positioned and has
00891     // things like opacity correct
00892     nsHTMLContainerFrame::SyncFrameViewAfterReflow(
00893                              presContext, 
00894                              this,
00895                              view,
00896                              &rect,
00897                              flags);
00898   } 
00899 
00900   if (IsBoxFrame())
00901     mState &= ~(NS_STATE_STYLE_CHANGE);
00902 
00903   return NS_OK;
00904 }
00905 
00906 nsresult
00907 nsIFrame::Redraw(nsBoxLayoutState& aState,
00908                  const nsRect*   aDamageRect,
00909                  PRBool          aImmediate)
00910 {
00911   if (aState.PaintingDisabled())
00912     return NS_OK;
00913 
00914   const nsHTMLReflowState* s = aState.GetReflowState();
00915   if (s) {
00916     if (s->reason != eReflowReason_Incremental)
00917       return NS_OK;
00918   }
00919 
00920   nsRect damageRect(0,0,0,0);
00921   if (aDamageRect)
00922     damageRect = *aDamageRect;
00923   else
00924     damageRect = GetOverflowRect();
00925 
00926   Invalidate(damageRect, aImmediate);
00927 
00928   return NS_OK;
00929 }
00930 
00931 PRBool 
00932 nsIBox::AddCSSPrefSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize)
00933 {
00934     PRBool widthSet = PR_FALSE;
00935     PRBool heightSet = PR_FALSE;
00936 
00937     // add in the css min, max, pref
00938     const nsStylePosition* position = aBox->GetStylePosition();
00939 
00940     // see if the width or height was specifically set
00941     if (position->mWidth.GetUnit() == eStyleUnit_Coord)  {
00942         aSize.width = position->mWidth.GetCoordValue();
00943         widthSet = PR_TRUE;
00944     }
00945 
00946     if (position->mHeight.GetUnit() == eStyleUnit_Coord) {
00947         aSize.height = position->mHeight.GetCoordValue();     
00948         heightSet = PR_TRUE;
00949     }
00950     
00951     nsIContent* content = aBox->GetContent();
00952     // ignore 'height' and 'width' attributes if the actual element is not XUL
00953     // For example, we might be magic XUL frames whose primary content is an HTML
00954     // <select>
00955     if (content && content->IsContentOfType(nsIContent::eXUL)) {
00956         nsPresContext* presContext = aState.PresContext();
00957 
00958         nsAutoString value;
00959         PRInt32 error;
00960 
00961         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::width, value))
00962         {
00963             value.Trim("%");
00964 
00965             aSize.width =
00966               presContext->IntScaledPixelsToTwips(value.ToInteger(&error));
00967             widthSet = PR_TRUE;
00968         }
00969 
00970         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::height, value))
00971         {
00972             value.Trim("%");
00973 
00974             aSize.height = presContext->IntScaledPixelsToTwips(value.ToInteger(&error));
00975             heightSet = PR_TRUE;
00976         }
00977     }
00978 
00979     return (widthSet && heightSet);
00980 }
00981 
00982 
00983 PRBool 
00984 nsIBox::AddCSSMinSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize)
00985 {
00986 
00987     PRBool widthSet = PR_FALSE;
00988     PRBool heightSet = PR_FALSE;
00989     PRBool canOverride = PR_TRUE;
00990 
00991     // See if a native theme wants to supply a minimum size.
00992     const nsStyleDisplay* display = aBox->GetStyleDisplay();
00993     if (display->mAppearance) {
00994       nsITheme *theme = aState.PresContext()->GetTheme();
00995       if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) {
00996         nsSize size;
00997         const nsHTMLReflowState* reflowState = aState.GetReflowState();
00998         if (reflowState) {
00999           theme->GetMinimumWidgetSize(reflowState->rendContext, aBox,
01000                                       display->mAppearance, &size, &canOverride);
01001           float p2t = aState.PresContext()->ScaledPixelsToTwips();
01002           if (size.width) {
01003             aSize.width = NSIntPixelsToTwips(size.width, p2t);
01004             widthSet = PR_TRUE;
01005           }
01006           if (size.height) {
01007             aSize.height = NSIntPixelsToTwips(size.height, p2t);
01008             heightSet = PR_TRUE;
01009           }
01010         }
01011       }
01012     }
01013 
01014     // add in the css min, max, pref
01015     const nsStylePosition* position = aBox->GetStylePosition();
01016 
01017     // same for min size. Unfortunately min size is always set to 0. So for now
01018     // we will assume 0 means not set.
01019     if (position->mMinWidth.GetUnit() == eStyleUnit_Coord) {
01020         nscoord min = position->mMinWidth.GetCoordValue();
01021         if (min && (!widthSet || (min > aSize.width && canOverride))) {
01022            aSize.width = min;
01023            widthSet = PR_TRUE;
01024         }
01025     } else if (position->mMinWidth.GetUnit() == eStyleUnit_Percent) {
01026         float min = position->mMinWidth.GetPercentValue();
01027         NS_ASSERTION(min == 0.0f, "Non-zero percentage values not currently supported");
01028         aSize.width = 0;
01029         widthSet = PR_TRUE;
01030     }
01031 
01032     if (position->mMinHeight.GetUnit() == eStyleUnit_Coord) {
01033         nscoord min = position->mMinHeight.GetCoordValue();
01034         if (min && (!heightSet || (min > aSize.height && canOverride))) {
01035            aSize.height = min;
01036            heightSet = PR_TRUE;
01037         }
01038     } else if (position->mMinHeight.GetUnit() == eStyleUnit_Percent) {
01039         float min = position->mMinHeight.GetPercentValue();
01040         NS_ASSERTION(min == 0.0f, "Non-zero percentage values not currently supported");
01041         aSize.height = 0;
01042         heightSet = PR_TRUE;
01043     }
01044 
01045     nsIContent* content = aBox->GetContent();
01046     if (content) {
01047         nsPresContext* presContext = aState.PresContext();
01048 
01049         nsAutoString value;
01050         PRInt32 error;
01051 
01052         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsXULAtoms::minwidth, value))
01053         {
01054             value.Trim("%");
01055 
01056             nscoord val =
01057               presContext->IntScaledPixelsToTwips(value.ToInteger(&error));
01058             if (val > aSize.width)
01059               aSize.width = val;
01060             widthSet = PR_TRUE;
01061         }
01062 
01063         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsXULAtoms::minheight, value))
01064         {
01065             value.Trim("%");
01066 
01067             nscoord val =
01068               presContext->IntScaledPixelsToTwips(value.ToInteger(&error));
01069             if (val > aSize.height)
01070               aSize.height = val;
01071 
01072             heightSet = PR_TRUE;
01073         }
01074     }
01075 
01076     return (widthSet && heightSet);
01077 }
01078 
01079 PRBool 
01080 nsIBox::AddCSSMaxSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize)
01081 {  
01082 
01083     PRBool widthSet = PR_FALSE;
01084     PRBool heightSet = PR_FALSE;
01085 
01086     // add in the css min, max, pref
01087     const nsStylePosition* position = aBox->GetStylePosition();
01088 
01089     // and max
01090     if (position->mMaxWidth.GetUnit() == eStyleUnit_Coord) {
01091         nscoord max = position->mMaxWidth.GetCoordValue();
01092         aSize.width = max;
01093         widthSet = PR_TRUE;
01094     }
01095 
01096     if (position->mMaxHeight.GetUnit() == eStyleUnit_Coord) {
01097         nscoord max = position->mMaxHeight.GetCoordValue();
01098         aSize.height = max;
01099         heightSet = PR_TRUE;
01100     }
01101 
01102     nsIContent* content = aBox->GetContent();
01103     if (content) {
01104         nsPresContext* presContext = aState.PresContext();
01105 
01106         nsAutoString value;
01107         PRInt32 error;
01108 
01109         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsXULAtoms::maxwidth, value))
01110         {
01111             value.Trim("%");
01112 
01113             nscoord val =
01114               presContext->IntScaledPixelsToTwips(value.ToInteger(&error));
01115             aSize.width = val;
01116             widthSet = PR_TRUE;
01117         }
01118 
01119         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsXULAtoms::maxheight, value))
01120         {
01121             value.Trim("%");
01122 
01123             nscoord val =
01124               presContext->IntScaledPixelsToTwips(value.ToInteger(&error));
01125             aSize.height = val;
01126 
01127             heightSet = PR_TRUE;
01128         }
01129     }
01130 
01131     return (widthSet || heightSet);
01132 }
01133 
01134 PRBool 
01135 nsIBox::AddCSSFlex(nsBoxLayoutState& aState, nsIBox* aBox, nscoord& aFlex)
01136 {
01137     PRBool flexSet = PR_FALSE;
01138 
01139     // get the flexibility
01140     nsIContent* content = aBox->GetContent();
01141     if (content) {
01142         PRInt32 error;
01143         nsAutoString value;
01144 
01145         if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsXULAtoms::flex, value))
01146         {
01147             value.Trim("%");
01148             aFlex = value.ToInteger(&error);
01149             flexSet = PR_TRUE;
01150         }
01151         else {
01152           // No attribute value.  Check CSS.
01153           const nsStyleXUL* boxInfo = aBox->GetStyleXUL();
01154           if (boxInfo->mBoxFlex > 0.0f) {
01155             // The flex was defined in CSS.
01156             aFlex = (nscoord)boxInfo->mBoxFlex;
01157             flexSet = PR_TRUE;
01158           }
01159         }
01160     }
01161 
01162     return flexSet;
01163 }
01164 
01165 PRBool 
01166 nsIBox::AddCSSCollapsed(nsBoxLayoutState& aState, nsIBox* aBox, PRBool& aCollapsed)
01167 {
01168   aCollapsed = aBox->GetStyleVisibility()->mVisible ==
01169                NS_STYLE_VISIBILITY_COLLAPSE;
01170   return PR_TRUE;
01171 }
01172 
01173 PRBool 
01174 nsIBox::AddCSSOrdinal(nsBoxLayoutState& aState, nsIBox* aBox, PRUint32& aOrdinal)
01175 {
01176   PRBool ordinalSet = PR_FALSE;
01177   
01178   // get the flexibility
01179   nsIContent* content = aBox->GetContent();
01180   if (content) {
01181     PRInt32 error;
01182     nsAutoString value;
01183 
01184     if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsXULAtoms::ordinal, value)) {
01185       aOrdinal = value.ToInteger(&error);
01186       ordinalSet = PR_TRUE;
01187     }
01188     else {
01189       // No attribute value.  Check CSS.
01190       const nsStyleXUL* boxInfo = aBox->GetStyleXUL();
01191       if (boxInfo->mBoxOrdinal > 1) {
01192         // The ordinal group was defined in CSS.
01193         aOrdinal = (nscoord)boxInfo->mBoxOrdinal;
01194         ordinalSet = PR_TRUE;
01195       }
01196     }
01197   }
01198 
01199   return ordinalSet;
01200 }
01201 
01202 void
01203 nsBox::AddBorderAndPadding(nsSize& aSize)
01204 {
01205   AddBorderAndPadding(this, aSize);
01206 }
01207 
01208 void
01209 nsBox::AddMargin(nsSize& aSize)
01210 {
01211   AddMargin(this, aSize);
01212 }
01213 
01214 void
01215 nsBox::AddBorderAndPadding(nsIBox* aBox, nsSize& aSize)
01216 {
01217   nsMargin borderPadding(0,0,0,0);
01218   aBox->GetBorderAndPadding(borderPadding);
01219   AddMargin(aSize, borderPadding);
01220 }
01221 
01222 void
01223 nsBox::AddMargin(nsIBox* aChild, nsSize& aSize)
01224 {
01225   nsMargin margin(0,0,0,0);
01226   aChild->GetMargin(margin);
01227   AddMargin(aSize, margin);
01228 }
01229 
01230 void
01231 nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin)
01232 {
01233   if (aSize.width != NS_INTRINSICSIZE)
01234     aSize.width += aMargin.left + aMargin.right;
01235 
01236   if (aSize.height != NS_INTRINSICSIZE)
01237      aSize.height += aMargin.top + aMargin.bottom;
01238 }
01239 
01240 #ifdef DEBUG_LAYOUT
01241 void
01242 nsBox::AddInset(nsIBox* aBox, nsSize& aSize)
01243 {
01244   nsMargin margin(0,0,0,0);
01245   aBox->GetInset(margin);
01246   AddMargin(aSize, margin);
01247 }
01248 #endif
01249 
01250 void
01251 nsBox::BoundsCheck(nscoord& aMin, nscoord& aPref, nscoord& aMax)
01252 {
01253    if (aMax < aMin)
01254        aMax = aMin;
01255 
01256    if (aPref > aMax)
01257        aPref = aMax;
01258 
01259    if (aPref < aMin)
01260        aPref = aMin;
01261 }
01262 
01263 void
01264 nsBox::BoundsCheckMinMax(nsSize& aMinSize, nsSize& aMaxSize)
01265 {
01266   if (aMaxSize.width < aMinSize.width) {
01267     aMaxSize.width = aMinSize.width;
01268   }
01269 
01270   if (aMaxSize.height < aMinSize.height)
01271     aMaxSize.height = aMinSize.height;
01272 }
01273 
01274 void
01275 nsBox::BoundsCheck(nsSize& aMinSize, nsSize& aPrefSize, nsSize& aMaxSize)
01276 {
01277    BoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width);
01278    BoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height);
01279 }
01280 
01281 #ifdef DEBUG_LAYOUT
01282 nsresult
01283 nsBox::SetDebug(nsBoxLayoutState& aState, PRBool aDebug)
01284 {
01285     return NS_OK;
01286 }
01287 
01288 NS_IMETHODIMP
01289 nsBox::GetDebugBoxAt( const nsPoint& aPoint,
01290                       nsIBox**     aBox)
01291 {
01292   if (!mRect.Contains(aPoint))
01293     return NS_ERROR_FAILURE;
01294 
01295   nsIBox* child = nsnull;
01296   nsIBox* hit = nsnull;
01297   GetChildBox(&child);
01298 
01299   *aBox = nsnull;
01300   nsPoint tmp;
01301   tmp.MoveTo(aPoint.x - mRect.x, aPoint.y - mRect.y);
01302   while (nsnull != child) {
01303     nsresult rv = child->GetDebugBoxAt(tmp, &hit);
01304 
01305     if (NS_SUCCEEDED(rv) && hit) {
01306       *aBox = hit;
01307     }
01308     child->GetNextBox(&child);
01309   }
01310 
01311   // found a child
01312   if (*aBox) {
01313     return NS_OK;
01314   }
01315 
01316  // see if it is in our in our insets
01317   nsMargin m;
01318   GetBorderAndPadding(m);
01319 
01320   nsRect rect(mRect);
01321   rect.Deflate(m);
01322   if (rect.Contains(aPoint)) {
01323     GetInset(m);
01324     rect.Deflate(m);
01325     if (!rect.Contains(aPoint)) {
01326       *aBox = this;
01327       return NS_OK;
01328     }
01329   }
01330 
01331   return NS_ERROR_FAILURE;
01332 }
01333 
01334 
01335 NS_IMETHODIMP
01336 nsBox::GetDebug(PRBool& aDebug)
01337 {
01338   aDebug = PR_FALSE;
01339   return NS_OK;
01340 }
01341 
01342 
01343 NS_IMETHODIMP 
01344 nsBox::GetInset(nsMargin& margin)
01345 {
01346   margin.SizeTo(0,0,0,0);
01347   return NS_OK;
01348 }
01349 
01350 #endif
01351 
01352 NS_IMETHODIMP
01353 nsBox::GetMouseThrough(PRBool& aMouseThrough)
01354 {
01355   if (mParent && mParent->IsBoxFrame())
01356     return mParent->GetMouseThrough(aMouseThrough);
01357 
01358   aMouseThrough = PR_FALSE;
01359   return NS_OK;
01360 }
01361 
01362 PRBool
01363 nsBox::GetDefaultFlex(PRInt32& aFlex) 
01364 { 
01365   aFlex = 0; 
01366   return PR_TRUE; 
01367 }
01368 
01369 NS_IMETHODIMP
01370 nsBox::GetIndexOf(nsIBox* aChild, PRInt32* aIndex)
01371 {
01372   // return -1. We have no children
01373   *aIndex = -1;
01374   return NS_OK;
01375 }