Back to index

lightning-sunbird  0.9+nobinonly
nsSprocketLayout.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  *   David Hyatt <hyatt@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 //
00041 // Eric Vaughan
00042 // Netscape Communications
00043 //
00044 // See documentation in associated header file
00045 //
00046 
00047 #include "nsBoxLayoutState.h"
00048 #include "nsSprocketLayout.h"
00049 #include "nsPresContext.h"
00050 #include "nsCOMPtr.h"
00051 #include "nsIContent.h"
00052 #include "nsIViewManager.h"
00053 #include "nsIView.h"
00054 #include "nsIPresShell.h"
00055 #include "nsHTMLContainerFrame.h"
00056 #include "nsBoxFrame.h"
00057 #include "nsHTMLAtoms.h"
00058 #include "nsXULAtoms.h"
00059 #include "nsBoxFrame.h"
00060 
00061 nsIBoxLayout* nsSprocketLayout::gInstance = nsnull;
00062 
00063 //#define DEBUG_GROW
00064 
00065 #define DEBUG_SPRING_SIZE 8
00066 #define DEBUG_BORDER_SIZE 2
00067 #define COIL_SIZE 8
00068 
00069 
00070 nsresult
00071 NS_NewSprocketLayout( nsIPresShell* aPresShell, nsCOMPtr<nsIBoxLayout>& aNewLayout)
00072 {
00073   if (!nsSprocketLayout::gInstance) {
00074     nsSprocketLayout::gInstance = new nsSprocketLayout();
00075     NS_IF_ADDREF(nsSprocketLayout::gInstance);
00076   }
00077   // we have not instance variables so just return our static one.
00078   aNewLayout = nsSprocketLayout::gInstance;
00079   return NS_OK;
00080 } 
00081 
00082 /*static*/ void
00083 nsSprocketLayout::Shutdown()
00084 {
00085   NS_IF_RELEASE(gInstance);
00086 }
00087 
00088 nsSprocketLayout::nsSprocketLayout()
00089 {
00090 }
00091 
00092 PRBool 
00093 nsSprocketLayout::IsHorizontal(nsIBox* aBox)
00094 {
00095    return (aBox->GetStateBits() & NS_STATE_IS_HORIZONTAL) != 0;
00096 }
00097 
00098 void
00099 nsSprocketLayout::GetFrameState(nsIBox* aBox, nsFrameState& aState)
00100 {
00101    aState = aBox->GetStateBits();
00102 }
00103 
00104 static PRUint8
00105 GetFrameDirection(nsIBox* aBox)
00106 {
00107    return aBox->GetStyleVisibility()->mDirection;
00108 }
00109 
00110 static void
00111 HandleBoxPack(nsIBox* aBox, const nsFrameState& aFrameState, nscoord& aX, nscoord& aY, 
00112               const nsRect& aOriginalRect, const nsRect& aClientRect)
00113 {
00114   // In the normal direction we lay out our kids in the positive direction (e.g., |x| will get
00115   // bigger for a horizontal box, and |y| will get bigger for a vertical box).  In the reverse
00116   // direction, the opposite is true.  We'll be laying out each child at a smaller |x| or
00117   // |y|.
00118   PRUint8 frameDirection = GetFrameDirection(aBox);
00119 
00120   if (aFrameState & NS_STATE_IS_HORIZONTAL) {
00121     if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
00122       // The normal direction. |x| increases as we move through our children.
00123       aX = aClientRect.x;
00124     }
00125     else {
00126       // The reverse direction. |x| decreases as we move through our children.
00127       aX = aClientRect.x + aOriginalRect.width;
00128     }
00129     // |y| is always in the normal direction in horizontal boxes
00130     aY = aClientRect.y;    
00131   }
00132   else {
00133     // take direction property into account for |x| in vertical boxes
00134     if (frameDirection == NS_STYLE_DIRECTION_LTR) {
00135       // The normal direction. |x| increases as we move through our children.
00136       aX = aClientRect.x;
00137     }
00138     else {
00139       // The reverse direction. |x| decreases as we move through our children.
00140       aX = aClientRect.x + aOriginalRect.width;
00141     }
00142     if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
00143       // The normal direction. |y| increases as we move through our children.
00144       aY = aClientRect.y;
00145     }
00146     else {
00147       // The reverse direction. |y| decreases as we move through our children.
00148       aY = aClientRect.y + aOriginalRect.height;
00149     }
00150   }
00151 
00152   // Get our pack/alignment information.
00153   nsIBox::Halignment halign;
00154   nsIBox::Valignment valign;
00155   aBox->GetVAlign(valign);
00156   aBox->GetHAlign(halign);
00157 
00158   // The following code handles box PACKING.  Packing comes into play in the case where the computed size for 
00159   // all of our children (now stored in our client rect) is smaller than the size available for
00160   // the box (stored in |aOriginalRect|).  
00161   // 
00162   // Here we adjust our |x| and |y| variables accordingly so that we start at the beginning,
00163   // middle, or end of the box.
00164   //
00165   // XXXdwh JUSTIFY needs to be implemented!
00166   if (aFrameState & NS_STATE_IS_HORIZONTAL) {
00167     switch(halign) {
00168       case nsBoxFrame::hAlign_Left:
00169         break; // Nothing to do.  The default initialized us properly.
00170 
00171       case nsBoxFrame::hAlign_Center:
00172         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
00173           aX += (aOriginalRect.width - aClientRect.width)/2;
00174         else 
00175           aX -= (aOriginalRect.width - aClientRect.width)/2;
00176         break;
00177 
00178       case nsBoxFrame::hAlign_Right:
00179         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
00180           aX += (aOriginalRect.width - aClientRect.width);
00181         else
00182           aX -= (aOriginalRect.width - aClientRect.width);
00183         break; // Nothing to do for the reverse dir.  The default initialized us properly.
00184     }
00185   } else {
00186     switch(valign) {
00187       case nsBoxFrame::vAlign_Top:
00188       case nsBoxFrame::vAlign_BaseLine: // This value is technically impossible to specify for pack.
00189         break;  // Don't do anything.  We were initialized correctly.
00190 
00191       case nsBoxFrame::vAlign_Middle:
00192         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
00193           aY += (aOriginalRect.height - aClientRect.height)/2;
00194         else
00195           aY -= (aOriginalRect.height - aClientRect.height)/2;
00196         break;
00197 
00198       case nsBoxFrame::vAlign_Bottom:
00199         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
00200           aY += (aOriginalRect.height - aClientRect.height);
00201         else
00202           aY -= (aOriginalRect.height - aClientRect.height);
00203         break;
00204     }
00205   }
00206 }
00207 
00208 NS_IMETHODIMP
00209 nsSprocketLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
00210 {
00211   // See if we are collapsed. If we are, then simply iterate over all our
00212   // children and give them a rect of 0 width and height.
00213   PRBool collapsed = PR_FALSE;
00214   aBox->IsCollapsed(aState, collapsed);
00215   if (collapsed) {
00216     nsIBox* child;
00217     aBox->GetChildBox(&child);
00218     while(child) 
00219     {
00220       nsBoxFrame::LayoutChildAt(aState, child, nsRect(0,0,0,0));  
00221       child->GetNextBox(&child);
00222     }
00223     return NS_OK;
00224   }
00225 
00226   aState.PushStackMemory();
00227 
00228   // ----- figure out our size ----------
00229   nsRect contentRect;
00230   aBox->GetContentRect(contentRect);
00231 
00232   // -- make sure we remove our border and padding  ----
00233   nsRect clientRect;
00234   aBox->GetClientRect(clientRect);
00235 
00236   // |originalClientRect| represents the rect of the entire box (excluding borders
00237   // and padding).  We store it here because we're going to use |clientRect| to hold
00238   // the required size for all our kids.  As an example, consider an hbox with a
00239   // specified width of 300.  If the kids total only 150 pixels of width, then
00240   // we have 150 pixels left over.  |clientRect| is going to hold a width of 150 and
00241   // is going to be adjusted based off the value of the PACK property.  If flexible
00242   // objects are in the box, then the two rects will match.
00243   nsRect originalClientRect(clientRect);
00244 
00245   // The frame state contains cached knowledge about our box, such as our orientation
00246   // and direction.
00247   nsFrameState frameState = 0;
00248   GetFrameState(aBox, frameState);
00249 
00250   // Build a list of our children's desired sizes and computed sizes
00251   nsBoxSize*         boxSizes = nsnull;
00252   nsComputedBoxSize* computedBoxSizes = nsnull;
00253 
00254   nscoord maxAscent = 0;
00255   aBox->GetAscent(aState, maxAscent);
00256 
00257   nscoord min = 0;
00258   nscoord max = 0;
00259   PRInt32 flexes = 0;
00260   PopulateBoxSizes(aBox, aState, boxSizes, computedBoxSizes, min, max, flexes);
00261   
00262   // The |size| variable will hold the total size of children along the axis of
00263   // the box.  Continuing with the example begun in the comment above, size would
00264   // be 150 pixels.
00265   nscoord size = clientRect.width;
00266   if (!IsHorizontal(aBox))
00267     size = clientRect.height;
00268   ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes);
00269 
00270   // After the call to ComputeChildSizes, the |size| variable contains the
00271   // total required size of all the children.  We adjust our clientRect in the
00272   // appropriate dimension to match this size.  In our example, we now assign
00273   // 150 pixels into the clientRect.width.
00274   //
00275   // The variables |min| and |max| hold the minimum required size box must be 
00276   // in the OPPOSITE orientation, e.g., for a horizontal box, |min| is the minimum
00277   // height we require to enclose our children, and |max| is the maximum height
00278   // required to enclose our children.
00279   if (IsHorizontal(aBox)) {
00280     clientRect.width = size;
00281     if (clientRect.height < min)
00282       clientRect.height = min;
00283 
00284     if (frameState & NS_STATE_AUTO_STRETCH) {
00285       if (clientRect.height > max)
00286         clientRect.height = max;
00287     }
00288   } else {
00289     clientRect.height = size;
00290     if (clientRect.width < min)
00291       clientRect.width = min;
00292 
00293     if (frameState & NS_STATE_AUTO_STRETCH) {
00294       if (clientRect.width > max)
00295         clientRect.width = max;
00296     }
00297   }
00298 
00299   // With the sizes computed, now it's time to lay out our children.
00300   PRBool needsRedraw = PR_FALSE;
00301   PRBool finished;
00302   nscoord passes = 0;
00303 
00304   // We flow children at their preferred locations (along with the appropriate computed flex).  
00305   // After we flow a child, it is possible that the child will change its size.  If/when this happens,
00306   // we have to do another pass.  Typically only 2 passes are required, but the code is prepared to
00307   // do as many passes as are necessary to achieve equilibrium.
00308   nscoord x = 0;
00309   nscoord y = 0;
00310   nscoord origX = 0;
00311   nscoord origY = 0;
00312 
00313   // |childResized| lets us know if a child changed its size after we attempted to lay it out at
00314   // the specified size.  If this happens, we usually have to do another pass.
00315   PRBool childResized = PR_FALSE;
00316 
00317   // |passes| stores our number of passes.  If for any reason we end up doing more than, say, 10
00318   // passes, we assert to indicate that something is seriously screwed up.
00319   passes = 0;
00320   do 
00321   { 
00322 #ifdef DEBUG_REFLOW
00323     if (passes > 0) {
00324       AddIndents();
00325       printf("ChildResized doing pass: %d\n", passes);
00326     }
00327 #endif 
00328 
00329     // Always assume that we're done.  This will change if, for example, children don't stay
00330     // the same size after being flowed.
00331     finished = PR_TRUE;
00332 
00333     // Handle box packing.
00334     HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
00335 
00336     // Now that packing is taken care of we set up a few additional
00337     // tracking variables.
00338     origX = x;
00339     origY = y;
00340 
00341     nscoord nextX = x;
00342     nscoord nextY = y;
00343 
00344     // Now we iterate over our box children and our box size lists in 
00345     // parallel.  For each child, we look at its sizes and figure out
00346     // where to place it.
00347     nsComputedBoxSize* childComputedBoxSize = computedBoxSizes;
00348     nsBoxSize* childBoxSize                 = boxSizes;
00349 
00350     nsIBox* child = nsnull;
00351     aBox->GetChildBox(&child);
00352 
00353     PRInt32 count = 0;
00354     while (child || (childBoxSize && childBoxSize->bogus))
00355     { 
00356       // If for some reason, our lists are not the same length, we guard
00357       // by bailing out of the loop.
00358       if (childBoxSize == nsnull) {
00359         NS_NOTREACHED("Lists not the same length.");
00360         break;
00361       }
00362         
00363       nscoord width = clientRect.width;
00364       nscoord height = clientRect.height;
00365 
00366       nsSize prefSize(0,0);
00367       nsSize minSize(0,0);
00368       nsSize maxSize(0,0);
00369       
00370       if (!childBoxSize->bogus) {
00371         // We have a valid box size entry.  This entry already contains information about our
00372         // sizes along the axis of the box (e.g., widths in a horizontal box).  If our default
00373         // ALIGN is not stretch, however, then we also need to know the child's size along the
00374         // opposite axis.
00375         if (!(frameState & NS_STATE_AUTO_STRETCH)) {
00376            child->GetPrefSize(aState, prefSize);
00377            child->GetMinSize(aState, minSize);
00378            child->GetMaxSize(aState, maxSize);
00379            nsBox::BoundsCheck(minSize, prefSize, maxSize);
00380        
00381            AddMargin(child, prefSize);
00382            width = PR_MIN(prefSize.width, originalClientRect.width);
00383            height = PR_MIN(prefSize.height, originalClientRect.height);
00384         }
00385       }
00386 
00387       // Obtain the computed size along the axis of the box for this child from the computedBoxSize entry.  
00388       // We store the result in |width| for horizontal boxes and |height| for vertical boxes.
00389       if (frameState & NS_STATE_IS_HORIZONTAL)
00390         width = childComputedBoxSize->size;
00391       else
00392         height = childComputedBoxSize->size;
00393       
00394       // Adjust our x/y for the left/right spacing.
00395       if (frameState & NS_STATE_IS_HORIZONTAL) {
00396         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
00397           x += (childBoxSize->left);
00398         else
00399           x -= (childBoxSize->right);
00400       } else {
00401         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
00402           y += (childBoxSize->left);
00403         else
00404           y -= (childBoxSize->right);
00405       }
00406 
00407       nextX = x;
00408       nextY = y;
00409 
00410       // Now we build a child rect.
00411       nscoord rectX = x;
00412       nscoord rectY = y;
00413       if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
00414         if (frameState & NS_STATE_IS_HORIZONTAL)
00415           rectX -= width;
00416         else
00417           rectY -= height;
00418       }
00419 
00420       // We now create an accurate child rect based off our computed size information.
00421       nsRect childRect(rectX, rectY, width, height);
00422 
00423       // Sanity check against our clientRect.  It is possible that a child specified
00424       // a size that is too large to fit.  If that happens, then we have to grow
00425       // our client rect.  Remember, clientRect is not the total rect of the enclosing
00426       // box.  It currently holds our perception of how big the children needed to
00427       // be.
00428       if (childRect.width > clientRect.width || childRect.height > clientRect.height) {
00429         if (childRect.width > clientRect.width)
00430           clientRect.width = childRect.width;
00431 
00432         if (childRect.height > clientRect.height)
00433           clientRect.height = childRect.height;
00434       }
00435     
00436       // |x|, |y|, |nextX|, and |nextY| are updated by this function call.  This call
00437       // also deals with box ALIGNMENT (when stretching is not turned on).
00438       ComputeChildsNextPosition(aBox, child, 
00439                                 x, 
00440                                 y, 
00441                                 nextX, 
00442                                 nextY, 
00443                                 childRect, 
00444                                 originalClientRect, 
00445                                 childBoxSize->ascent,
00446                                 maxAscent);
00447 
00448       // Now we update our nextX/Y along our axis and we update our x/y along the opposite
00449       // axis (since a non-stretching alignment could have caused an adjustment).
00450       if (frameState & NS_STATE_IS_HORIZONTAL) {
00451         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
00452           nextX += (childBoxSize->right);
00453         else
00454           nextX -= (childBoxSize->left);
00455         childRect.y = y;
00456       }
00457       else {
00458         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
00459           nextY += (childBoxSize->right);
00460         else 
00461           nextY -= (childBoxSize->left);
00462         childRect.x = x;
00463       }
00464       
00465       // If we encounter a completely bogus box size, we just leave this child completely
00466       // alone and continue through the loop to the next child.
00467       if (childBoxSize->bogus) 
00468       {
00469         childComputedBoxSize = childComputedBoxSize->next;
00470         childBoxSize = childBoxSize->next;
00471         count++;
00472         x = nextX;
00473         y = nextY;
00474         continue;
00475       }
00476 
00477       nsMargin margin(0,0,0,0);
00478 
00479       PRBool layout = PR_TRUE;
00480 
00481       // Deflate the rect of our child by its margin.
00482       child->GetMargin(margin);
00483       childRect.Deflate(margin);
00484       if (childRect.width < 0)
00485         childRect.width = 0;
00486       if (childRect.height < 0)
00487         childRect.height = 0;
00488 
00489       // Now we're trying to figure out if we have to lay out this child, i.e., to call
00490       // the child's Layout method.
00491       if (passes > 0) {
00492         layout = PR_FALSE;
00493       } else {
00494         // Always perform layout if we are dirty or have dirty children
00495         PRBool dirty = PR_FALSE;           
00496         PRBool dirtyChildren = PR_FALSE;           
00497         child->IsDirty(dirty);
00498         child->HasDirtyChildren(dirtyChildren);
00499         if (!(dirty || dirtyChildren) && aState.LayoutReason() != nsBoxLayoutState::Initial)
00500           layout = PR_FALSE;
00501       }
00502 
00503       // We computed a childRect.  Now we want to set the bounds of the child to be that rect.
00504       // If our old rect is different, then we know our size changed and we cache that fact
00505       // in the |sizeChanged| variable.
00506       nsRect oldRect(child->GetRect());
00507       PRBool sizeChanged = PR_FALSE;
00508 
00509       child->SetBounds(aState, childRect);
00510       sizeChanged = (childRect.width != oldRect.width || childRect.height != oldRect.height);
00511 
00512       PRBool possibleRedraw = PR_FALSE;
00513 
00514       if (sizeChanged) {
00515         // Our size is different.  Sanity check against our maximum allowed size to ensure
00516         // we didn't exceed it.
00517         child->GetMinSize(aState, minSize);
00518         child->GetMaxSize(aState, maxSize);
00519         nsBox::BoundsCheckMinMax(minSize, maxSize);
00520 
00521         // make sure the size is in our max size.
00522         if (childRect.width > maxSize.width)
00523           childRect.width = maxSize.width;
00524 
00525         if (childRect.height > maxSize.height)
00526           childRect.height = maxSize.height;
00527            
00528         // set it again
00529         child->SetBounds(aState, childRect);
00530 
00531         // Since the child changed size, we know a redraw is probably going to be required.
00532         possibleRedraw = PR_TRUE;
00533       }
00534 
00535       // if something moved then we might need to redraw
00536       if (oldRect.x != childRect.x || oldRect.y != childRect.y)
00537           possibleRedraw = PR_TRUE;
00538 
00539       // If we already determined that layout was required or if our size has changed, then
00540       // we make sure to call layout on the child, since its children may need to be shifted
00541       // around as a result of the size change.
00542       if (layout || sizeChanged)
00543         child->Layout(aState);
00544       
00545       // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout. 
00546       // We have to check for this.
00547       nsRect newChildRect(child->GetRect());
00548 
00549       if (newChildRect != childRect) {
00550 #ifdef DEBUG_GROW
00551         child->DumpBox(stdout);
00552         printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height);
00553 #endif
00554         newChildRect.Inflate(margin);
00555         childRect.Inflate(margin);
00556 
00557         // The child changed size during layout.  The ChildResized method handles this
00558         // scenario.
00559         ChildResized(aBox,
00560                      aState, 
00561                      child,
00562                      childBoxSize,
00563                      childComputedBoxSize,
00564                      boxSizes, 
00565                      computedBoxSizes, 
00566                      childRect,
00567                      newChildRect,
00568                      clientRect,
00569                      flexes,
00570                      finished);
00571 
00572         // We note that a child changed size, which means that another pass will be required.
00573         childResized = PR_TRUE;
00574 
00575         // Now that a child resized, it's entirely possible that OUR rect is too small.  Now we
00576         // ensure that |originalClientRect| is grown to accommodate the size of |clientRect|.
00577         if (clientRect.width > originalClientRect.width || clientRect.height > originalClientRect.height) {
00578           if (clientRect.width > originalClientRect.width)
00579             originalClientRect.width = clientRect.width;
00580 
00581           if (clientRect.height > originalClientRect.height)
00582             originalClientRect.height = clientRect.height;
00583         }
00584 
00585         if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
00586           // Our childRect had its XMost() or YMost() (depending on our layout
00587           // direction), positioned at a certain point.  Ensure that the
00588           // newChildRect satisfies the same constraint.  Note that this is
00589           // just equivalent to adjusting the x/y by the difference in
00590           // width/height between childRect and newChildRect.  So we don't need
00591           // to reaccount for the left and right of the box layout state again.
00592           if (frameState & NS_STATE_IS_HORIZONTAL)
00593             newChildRect.x = childRect.XMost() - newChildRect.width;
00594           else
00595             newChildRect.y = childRect.YMost() - newChildRect.height;
00596         }
00597 
00598         // If the child resized then recompute its position.
00599         ComputeChildsNextPosition(aBox, child, 
00600                                   x, 
00601                                   y, 
00602                                   nextX, 
00603                                   nextY, 
00604                                   newChildRect, 
00605                                   originalClientRect, 
00606                                   childBoxSize->ascent,
00607                                   maxAscent);
00608 
00609         // Only update the variable in the opposite axis (since this is only here to deal with
00610         // a non-stretching ALIGNMENT)
00611         if (frameState & NS_STATE_IS_HORIZONTAL)
00612           newChildRect.y = y;
00613         else
00614           newChildRect.x = x;
00615          
00616         if (newChildRect.width >= margin.left + margin.right && newChildRect.height >= margin.top + margin.bottom) 
00617           newChildRect.Deflate(margin);
00618 
00619         if (childRect.width >= margin.left + margin.right && childRect.height >= margin.top + margin.bottom) 
00620           childRect.Deflate(margin);
00621             
00622         child->SetBounds(aState, newChildRect);
00623 
00624         // If we are the first box that changed size, then we don't need to do a second pass
00625         if (count == 0)
00626           finished = PR_TRUE;
00627       }
00628 
00629       // Now update our x/y finally.
00630       x = nextX;
00631       y = nextY;
00632      
00633       // If we get here and |possibleRedraw| is still set, then it's official.  We do need a repaint.
00634       if (possibleRedraw)
00635         needsRedraw = PR_TRUE;
00636 
00637       // Move to the next child.
00638       childComputedBoxSize = childComputedBoxSize->next;
00639       childBoxSize = childBoxSize->next;
00640 
00641       child->GetNextBox(&child);
00642       count++;
00643     }
00644 
00645     // Sanity-checking code to ensure we don't do an infinite # of passes.
00646     passes++;
00647     NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!");
00648     if (passes > 10)
00649       break;
00650   } while (PR_FALSE == finished);
00651 
00652   // Get rid of our size lists.
00653   while(boxSizes)
00654   {
00655     nsBoxSize* toDelete = boxSizes;
00656     boxSizes = boxSizes->next;
00657     delete toDelete;
00658   }
00659 
00660   while(computedBoxSizes)
00661   {
00662     nsComputedBoxSize* toDelete = computedBoxSizes;
00663     computedBoxSizes = computedBoxSizes->next;
00664     delete toDelete;
00665   }
00666 
00667   if (childResized) {
00668     // See if one of our children forced us to get bigger
00669     nsRect tmpClientRect(originalClientRect);
00670     nsMargin bp(0,0,0,0);
00671     aBox->GetBorderAndPadding(bp);
00672     tmpClientRect.Inflate(bp);
00673     aBox->GetInset(bp);
00674     tmpClientRect.Inflate(bp);
00675 
00676     if (tmpClientRect.width > contentRect.width || tmpClientRect.height > contentRect.height)
00677     {
00678       // if it did reset our bounds.
00679       nsRect bounds(aBox->GetRect());
00680       if (tmpClientRect.width > contentRect.width)
00681         bounds.width = tmpClientRect.width;
00682 
00683       if (tmpClientRect.height > contentRect.height)
00684         bounds.height = tmpClientRect.height;
00685 
00686       aBox->SetBounds(aState, bounds);
00687     }
00688   }
00689 
00690   // Because our size grew, we now have to readjust because of box packing.  Repack
00691   // in order to update our x and y to the correct values.
00692   HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
00693 
00694   // Compare against our original x and y and only worry about adjusting the children if
00695   // we really did have to change the positions because of packing (typically for 'center'
00696   // or 'end' pack values).
00697   if (x != origX || y != origY) {
00698     nsIBox* child = nsnull;
00699     // reposition all our children
00700     aBox->GetChildBox(&child);
00701 
00702     while (child) 
00703     {
00704       nsRect childRect(child->GetRect());
00705       childRect.x += (x - origX);
00706       childRect.y += (y - origY);
00707       child->SetBounds(aState, childRect);
00708       child->GetNextBox(&child);
00709     }
00710   }
00711 
00712   // Now do our redraw.
00713   if (needsRedraw)
00714     aBox->Redraw(aState);
00715 
00716   aState.PopStackMemory();
00717 
00718   // That's it!  If you made it this far without having a nervous breakdown, 
00719   // congratulations!  Go get yourself a beer.
00720   return NS_OK;
00721 }
00722 
00723 void
00724 nsSprocketLayout::PopulateBoxSizes(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nsComputedBoxSize*& aComputedBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, PRInt32& aFlexes)
00725 {
00726   // used for the equal size flag
00727   nscoord biggestPrefWidth = 0;
00728   nscoord biggestMinWidth = 0;
00729   nscoord smallestMaxWidth = NS_INTRINSICSIZE;
00730 
00731   nsFrameState frameState = 0;
00732   GetFrameState(aBox, frameState);
00733 
00734   //if (frameState & NS_STATE_CURRENTLY_IN_DEBUG)
00735   //   printf("In debug\n");
00736 
00737   aMinSize = 0;
00738   aMaxSize = NS_INTRINSICSIZE;
00739 
00740   PRBool isHorizontal;
00741 
00742   if (IsHorizontal(aBox))
00743      isHorizontal = PR_TRUE;
00744   else
00745      isHorizontal = PR_FALSE;
00746 
00747   // this is a nice little optimization
00748   // it turns out that if we only have 1 flexable child
00749   // then it does not matter what its preferred size is
00750   // there is nothing to flex it relative. This is great
00751   // because we can avoid asking for a preferred size in this
00752   // case. Why is this good? Well you might have html inside it
00753   // and asking html for its preferred size is rather expensive.
00754   // so we can just optimize it out this way.
00755 
00756   // set flexes
00757   nsIBox* child = nsnull;
00758   aBox->GetChildBox(&child);
00759 
00760   aFlexes = 0;
00761   nsBoxSize* currentBox = nsnull;
00762 
00763 #if 0
00764   nsBoxSize* start = aBoxSizes;
00765   
00766   while(child)
00767   {
00768     // ok if we started with a list move down the list
00769     // until we reach the end. Then start looking at childen.
00770     // This feature is used extensively for Grid.
00771     nscoord flex = 0;    
00772 
00773     if (!start) {
00774       if (!currentBox) {
00775         aBoxSizes      = new (aState) nsBoxSize();
00776         currentBox      = aBoxSizes;
00777       } else {
00778         currentBox->next      = new (aState) nsBoxSize();
00779         currentBox      = currentBox->next;
00780       }
00781     
00782 
00783       child->GetFlex(aState, flex);
00784       PRBool collapsed = PR_FALSE;    
00785       child->IsCollapsed(aState, collapsed);
00786 
00787       currentBox->flex = flex;
00788       currentBox->collapsed = collapsed;
00789     } else {
00790       flex = start->flex;
00791       start = start->next;
00792     }
00793     
00794     if (flex > 0) 
00795        aFlexes++;
00796    
00797     child->GetNextBox(&child);
00798   }
00799 #endif
00800 
00801   // get pref, min, max
00802   aBox->GetChildBox(&child);
00803   currentBox = aBoxSizes;
00804   nsBoxSize* last = nsnull;
00805 
00806   nscoord maxFlex = 0;
00807   PRInt32 childCount = 0;
00808 
00809   while(child)
00810   {
00811     ++childCount;
00812     nsSize pref(0,0);
00813     nsSize min(0,0);
00814     nsSize max(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
00815     nscoord ascent = 0;
00816 
00817     PRBool collapsed = PR_FALSE;    
00818     child->IsCollapsed(aState, collapsed);
00819 
00820     if (!collapsed) {
00821     // only one flexible child? Cool we will just make its preferred size
00822     // 0 then and not even have to ask for it.
00823     //if (flexes != 1)  {
00824 
00825       child->GetPrefSize(aState, pref);
00826       child->GetMinSize(aState, min);
00827       child->GetMaxSize(aState, max);
00828       child->GetAscent(aState, ascent);
00829       nsMargin margin;
00830       child->GetMargin(margin);
00831       ascent += margin.top;
00832     //}
00833 
00834       nsBox::BoundsCheck(min, pref, max);
00835 
00836       AddMargin(child, pref);
00837       AddMargin(child, min);
00838       AddMargin(child, max);
00839     }
00840 
00841     if (!currentBox) {
00842       // create one.
00843       currentBox = new (aState) nsBoxSize();
00844       if (!aBoxSizes) {
00845         aBoxSizes = currentBox;
00846         last = aBoxSizes;
00847       } else {
00848         last->next = currentBox;
00849         last = currentBox;
00850       }
00851 
00852       nscoord minWidth;
00853       nscoord maxWidth;
00854       nscoord prefWidth;
00855 
00856       // get sizes from child
00857       if (isHorizontal) {
00858           minWidth  = min.width;
00859           maxWidth  = max.width;
00860           prefWidth = pref.width;
00861       } else {
00862           minWidth = min.height;
00863           maxWidth = max.height;
00864           prefWidth = pref.height;
00865       }
00866 
00867       nscoord flex = 0;
00868       child->GetFlex(aState, flex);
00869 
00870       // set them if you collapsed you are not flexible.
00871       if (collapsed) {
00872         currentBox->flex = 0;
00873       }
00874       else {
00875         if (flex > maxFlex) {
00876           maxFlex = flex;
00877         }
00878         currentBox->flex = flex;
00879       }
00880 
00881       // we we specified all our children are equal size;
00882       if (frameState & NS_STATE_EQUAL_SIZE) {
00883 
00884         if (prefWidth > biggestPrefWidth) 
00885           biggestPrefWidth = prefWidth;
00886 
00887         if (minWidth > biggestMinWidth) 
00888           biggestMinWidth = minWidth;
00889 
00890         if (maxWidth < smallestMaxWidth) 
00891           smallestMaxWidth = maxWidth;
00892       } else { // not we can set our children right now.
00893         currentBox->pref    = prefWidth;
00894         currentBox->min     = minWidth;
00895         currentBox->max     = maxWidth;
00896       }
00897 
00898       NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,"Bad min, pref, max widths!");
00899 
00900     }
00901 
00902     if (!isHorizontal) {
00903       if (min.width > aMinSize)
00904         aMinSize = min.width;
00905 
00906       if (max.width < aMaxSize)
00907         aMaxSize = max.width;
00908 
00909     } else {
00910       if (min.height > aMinSize)
00911         aMinSize = min.height;
00912 
00913       if (max.height < aMaxSize)
00914         aMaxSize = max.height;
00915     }
00916 
00917     currentBox->ascent  = ascent;
00918     currentBox->collapsed = collapsed;
00919     aFlexes += currentBox->flex;
00920 
00921     child->GetNextBox(&child);
00922 
00923     last = currentBox;
00924     currentBox = currentBox->next;
00925 
00926   }
00927 
00928   if (childCount > 0) {
00929     nscoord maxAllowedFlex = nscoord_MAX / childCount;
00930   
00931     if (NS_UNLIKELY(maxFlex > maxAllowedFlex)) {
00932       // clamp all the flexes
00933       currentBox = aBoxSizes;
00934       while (currentBox) {
00935         currentBox->flex = PR_MIN(currentBox->flex, maxAllowedFlex);
00936         currentBox = currentBox->next;      
00937       }
00938     }
00939   }
00940 #ifdef DEBUG
00941   else {
00942     NS_ASSERTION(maxFlex == 0, "How did that happen?");
00943   }
00944 #endif
00945 
00946   // we we specified all our children are equal size;
00947   if (frameState & NS_STATE_EQUAL_SIZE) {
00948     currentBox = aBoxSizes;
00949 
00950     while(currentBox)
00951     {
00952       if (!currentBox->collapsed) {
00953         currentBox->pref = biggestPrefWidth;
00954         currentBox->min = biggestMinWidth;
00955         currentBox->max = smallestMaxWidth;
00956       } else {
00957         currentBox->pref = 0;
00958         currentBox->min = 0;
00959         currentBox->max = 0;
00960       }
00961       currentBox = currentBox->next;
00962     }
00963   }
00964 
00965 }
00966 
00967 void
00968 nsSprocketLayout::ComputeChildsNextPosition(nsIBox* aBox, 
00969                                       nsIBox* aChild, 
00970                                       nscoord& aCurX, 
00971                                       nscoord& aCurY, 
00972                                       nscoord& aNextX, 
00973                                       nscoord& aNextY, 
00974                                       const nsRect& aCurrentChildSize, 
00975                                       const nsRect& aBoxRect,
00976                                       nscoord childAscent,
00977                                       nscoord aMaxAscent)
00978 {
00979   nsFrameState frameState = 0;
00980   GetFrameState(aBox, frameState);
00981 
00982   nsIBox::Halignment halign;
00983   nsIBox::Valignment valign;
00984   aBox->GetVAlign(valign);
00985   aBox->GetHAlign(halign);
00986 
00987   if (IsHorizontal(aBox)) {
00988     // Handle alignment of a horizontal box's children.
00989     if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
00990       aNextX = aCurX + aCurrentChildSize.width;
00991     else aNextX = aCurX - aCurrentChildSize.width;
00992 
00993     if (frameState & NS_STATE_AUTO_STRETCH)
00994       aCurY = aBoxRect.y;
00995     else {
00996       switch (valign) 
00997       {
00998          case nsBoxFrame::vAlign_BaseLine:
00999              aCurY = aBoxRect.y + (aMaxAscent - childAscent);
01000          break;
01001 
01002          case nsBoxFrame::vAlign_Top:
01003              aCurY = aBoxRect.y;
01004              break;
01005          case nsBoxFrame::vAlign_Middle:
01006              aCurY = aBoxRect.y + (aBoxRect.height/2 - aCurrentChildSize.height/2);
01007              break;
01008          case nsBoxFrame::vAlign_Bottom:
01009              aCurY = aBoxRect.y + aBoxRect.height - aCurrentChildSize.height;
01010              break;
01011       }
01012     }
01013   } else {
01014     // Handle alignment of a vertical box's children.
01015     if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
01016       aNextY = aCurY + aCurrentChildSize.height;
01017     else
01018       aNextY = aCurY - aCurrentChildSize.height;
01019 
01020     if (frameState & NS_STATE_AUTO_STRETCH)
01021       aCurX = aBoxRect.x;
01022     else {
01023       PRUint8 frameDirection = GetFrameDirection(aBox);
01024       switch (halign) 
01025       {
01026          case nsBoxFrame::hAlign_Left:
01027            if (frameDirection == NS_STYLE_DIRECTION_LTR)
01028              aCurX = aBoxRect.x;
01029            else
01030              aCurX = aBoxRect.x + aBoxRect.width - aCurrentChildSize.width;
01031            break;
01032          case nsBoxFrame::hAlign_Center:
01033              aCurX = aBoxRect.x + (aBoxRect.width/2 - aCurrentChildSize.width/2);
01034              break;
01035          case nsBoxFrame::hAlign_Right:
01036            if (frameDirection == NS_STYLE_DIRECTION_LTR)
01037              aCurX = aBoxRect.x + aBoxRect.width - aCurrentChildSize.width;
01038            else
01039              aCurX = aBoxRect.x;
01040            break;
01041       }
01042     }
01043   }
01044 }
01045 
01046 void
01047 nsSprocketLayout::ChildResized(nsIBox* aBox,
01048                          nsBoxLayoutState& aState, 
01049                          nsIBox* aChild,
01050                          nsBoxSize* aChildBoxSize,
01051                          nsComputedBoxSize* aChildComputedSize,
01052                          nsBoxSize* aBoxSizes, 
01053                          nsComputedBoxSize* aComputedBoxSizes, 
01054                          const nsRect& aChildLayoutRect, 
01055                          nsRect& aChildActualRect, 
01056                          nsRect& aContainingRect,
01057                          PRInt32 aFlexes, 
01058                          PRBool& aFinished)
01059                          
01060 {
01061       nsRect childCurrentRect(aChildLayoutRect);
01062 
01063       PRBool isHorizontal = IsHorizontal(aBox);
01064       nscoord childLayoutWidth  = GET_WIDTH(aChildLayoutRect,isHorizontal);
01065       nscoord& childActualWidth  = GET_WIDTH(aChildActualRect,isHorizontal);
01066       nscoord& containingWidth   = GET_WIDTH(aContainingRect,isHorizontal);   
01067       
01068       //nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal);
01069       nscoord& childActualHeight = GET_HEIGHT(aChildActualRect,isHorizontal);
01070       nscoord& containingHeight  = GET_HEIGHT(aContainingRect,isHorizontal);
01071 
01072       PRBool recompute = PR_FALSE;
01073 
01074       // if we are a horizontal box see if the child will fit inside us.
01075       if ( childActualHeight > containingHeight) {
01076             // if we are a horizontal box and the the child it bigger than our height
01077 
01078             // ok if the height changed then we need to reflow everyone but us at the new height
01079             // so we will set the changed index to be us. And signal that we need a new pass.
01080 
01081             nsSize max(0,0);
01082             nsSize min(0,0);
01083             aChild->GetMaxSize(aState, max);
01084             aChild->GetMinSize(aState, min);
01085             nsBox::BoundsCheckMinMax(min, max);
01086             AddMargin(aChild, max);
01087 
01088             if (isHorizontal)
01089               childActualHeight = max.height < childActualHeight ? max.height : childActualHeight;
01090             else
01091               childActualHeight = max.width < childActualHeight ? max.width : childActualHeight;
01092 
01093             // only set if it changes
01094             if (childActualHeight > containingHeight) {
01095                  containingHeight = childActualHeight;
01096 
01097               // remember we do not need to clear the resized list because changing the height of a horizontal box
01098               // will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me
01099               // on this one.
01100               aFinished = PR_FALSE;
01101 
01102               // only recompute if there are flexes.
01103               if (aFlexes > 0) {
01104                 // relayout everything
01105                 recompute = PR_TRUE;
01106                 InvalidateComputedSizes(aComputedBoxSizes);
01107                 nsComputedBoxSize* node = aComputedBoxSizes;
01108 
01109                 while(node) {
01110                   node->resized = PR_FALSE;
01111                   node = node->next;
01112                 }
01113 
01114               }              
01115             }
01116       } 
01117       
01118       if (childActualWidth > childLayoutWidth) {
01119             nsSize max(0,0);
01120             nsSize min(0,0);
01121             aChild->GetMinSize(aState, min);
01122             aChild->GetMaxSize(aState, max);
01123             nsBox::BoundsCheckMinMax(min, max);
01124             AddMargin(aChild, max);
01125 
01126             // our width now becomes the new size
01127 
01128             if (isHorizontal)
01129               childActualWidth = max.width < childActualWidth ? max.width : childActualWidth;
01130             else
01131               childActualWidth = max.height < childActualWidth ? max.height : childActualWidth;
01132 
01133             if (childActualWidth > childLayoutWidth) {
01134                aChildComputedSize->size = childActualWidth;
01135                aChildBoxSize->min = childActualWidth;
01136                if (aChildBoxSize->pref < childActualWidth)
01137                   aChildBoxSize->pref = childActualWidth;
01138 
01139               // if we have flexible elements with us then reflex things. Otherwise we can skip doing it.
01140               if (aFlexes > 0) {
01141                 InvalidateComputedSizes(aComputedBoxSizes);
01142 
01143                 nsComputedBoxSize* node = aComputedBoxSizes;
01144                 aChildComputedSize->resized = PR_TRUE;
01145 
01146                 while(node) {
01147                   if (node->resized)
01148                       node->valid = PR_TRUE;
01149                 
01150                   node = node->next;
01151                 }
01152 
01153                 recompute = PR_TRUE;
01154                 aFinished = PR_FALSE;
01155               } else {
01156                 containingWidth += aChildComputedSize->size - childLayoutWidth;
01157               }              
01158             }
01159       }
01160 
01161       if (recompute)
01162             ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes, aComputedBoxSizes);
01163 
01164       if (childCurrentRect != aChildActualRect) {
01165         // the childRect includes the margin
01166         // make sure we remove it before setting 
01167         // the bounds.
01168         nsMargin margin(0,0,0,0);
01169         aChild->GetMargin(margin);
01170         nsRect rect(aChildActualRect);
01171         if (rect.width >= margin.left + margin.right && rect.height >= margin.top + margin.bottom) 
01172           rect.Deflate(margin);
01173 
01174         aChild->SetBounds(aState, rect);
01175         aChild->Layout(aState);
01176       }
01177 
01178 }
01179 
01180 void
01181 nsSprocketLayout::InvalidateComputedSizes(nsComputedBoxSize* aComputedBoxSizes)
01182 {
01183   while(aComputedBoxSizes) {
01184       aComputedBoxSizes->valid = PR_FALSE;
01185       aComputedBoxSizes = aComputedBoxSizes->next;
01186   }
01187 }
01188 
01189 void
01190 nsSprocketLayout::ComputeChildSizes(nsIBox* aBox,
01191                            nsBoxLayoutState& aState, 
01192                            nscoord& aGivenSize, 
01193                            nsBoxSize* aBoxSizes, 
01194                            nsComputedBoxSize*& aComputedBoxSizes)
01195 {  
01196 
01197   //nscoord onePixel = aState.PresContext()->IntScaledPixelsToTwips(1);
01198 
01199   PRInt32 sizeRemaining            = aGivenSize;
01200   PRInt32 spacerConstantsRemaining = 0;
01201 
01202    // ----- calculate the spacers constants and the size remaining -----
01203 
01204   if (!aComputedBoxSizes)
01205       aComputedBoxSizes = new (aState) nsComputedBoxSize();
01206   
01207   nsBoxSize*         boxSizes = aBoxSizes;
01208   nsComputedBoxSize* computedBoxSizes = aComputedBoxSizes;
01209   PRInt32 count = 0;
01210   PRInt32 validCount = 0;
01211 
01212   while (boxSizes) 
01213   {
01214 
01215     NS_ASSERTION((boxSizes->min <= boxSizes->pref && boxSizes->pref <= boxSizes->max),"bad pref, min, max size");
01216 
01217     
01218      // ignore collapsed children
01219   //  if (boxSizes->collapsed) 
01220   //  {
01221     //  computedBoxSizes->valid = PR_TRUE;
01222     //  computedBoxSizes->size = boxSizes->pref;
01223      // validCount++;
01224   //      boxSizes->flex = 0;
01225    // }// else {
01226     
01227       if (computedBoxSizes->valid) { 
01228         sizeRemaining -= computedBoxSizes->size;
01229         validCount++;
01230       } else {
01231           if (boxSizes->flex == 0)
01232           {
01233             computedBoxSizes->valid = PR_TRUE;
01234             computedBoxSizes->size = boxSizes->pref;
01235             validCount++;
01236           }
01237 
01238           spacerConstantsRemaining += boxSizes->flex;
01239           sizeRemaining -= boxSizes->pref;
01240       }
01241 
01242       sizeRemaining -= (boxSizes->left + boxSizes->right);
01243 
01244     //} 
01245 
01246     boxSizes = boxSizes->next;
01247 
01248     if (boxSizes && !computedBoxSizes->next) 
01249       computedBoxSizes->next = new (aState) nsComputedBoxSize();
01250 
01251     computedBoxSizes = computedBoxSizes->next;
01252     count++;
01253   }
01254 
01255   // everything accounted for?
01256   if (validCount < count)
01257   {
01258     // ----- Ok we are give a size to fit into so stretch or squeeze to fit
01259     // ----- Make sure we look at our min and max size
01260     PRBool limit = PR_TRUE;
01261     for (int pass=1; PR_TRUE == limit; pass++) 
01262     {
01263       limit = PR_FALSE;
01264       boxSizes = aBoxSizes;
01265       computedBoxSizes = aComputedBoxSizes;
01266 
01267       while (boxSizes) { 
01268 
01269         // ignore collapsed spacers
01270 
01271    //    if (!boxSizes->collapsed) {
01272       
01273           nscoord pref = 0;
01274           nscoord max  = NS_INTRINSICSIZE;
01275           nscoord min  = 0;
01276           nscoord flex = 0;
01277 
01278           pref = boxSizes->pref;
01279           min  = boxSizes->min;
01280           max  = boxSizes->max;
01281           flex = boxSizes->flex;
01282 
01283           // ----- look at our min and max limits make sure we aren't too small or too big -----
01284           if (!computedBoxSizes->valid) {
01285             PRInt32 newSize = pref + sizeRemaining*flex/spacerConstantsRemaining; //NSToCoordRound(float((sizeRemaining*flex)/spacerConstantsRemaining));
01286 
01287             if (newSize<=min) {
01288               computedBoxSizes->size = min;
01289               computedBoxSizes->valid = PR_TRUE;
01290               spacerConstantsRemaining -= flex;
01291               sizeRemaining += pref;
01292               sizeRemaining -= min;
01293               limit = PR_TRUE;
01294             } else if (newSize>=max) {
01295               computedBoxSizes->size = max;
01296               computedBoxSizes->valid = PR_TRUE;
01297               spacerConstantsRemaining -= flex;
01298               sizeRemaining += pref;
01299               sizeRemaining -= max;
01300               limit = PR_TRUE;
01301             }
01302           }
01303        // }
01304         boxSizes         = boxSizes->next;
01305         computedBoxSizes = computedBoxSizes->next;
01306       }
01307     }
01308   }          
01309 
01310   // ---- once we have removed and min and max issues just stretch us out in the remaining space
01311   // ---- or shrink us. Depends on the size remaining and the spacer constants
01312   aGivenSize = 0;
01313   boxSizes = aBoxSizes;
01314   computedBoxSizes = aComputedBoxSizes;
01315 
01316   while (boxSizes) { 
01317 
01318     // ignore collapsed spacers
01319   //  if (!(boxSizes && boxSizes->collapsed)) {
01320     
01321       nscoord pref = 0;
01322       nscoord flex = 0;
01323       pref = boxSizes->pref;
01324       flex = boxSizes->flex;
01325 
01326       if (!computedBoxSizes->valid) {
01327         computedBoxSizes->size = pref + flex*sizeRemaining/spacerConstantsRemaining; //NSToCoordFloor(float((flex*sizeRemaining)/spacerConstantsRemaining));
01328         computedBoxSizes->valid = PR_TRUE;
01329       }
01330 
01331       aGivenSize += (boxSizes->left + boxSizes->right);
01332       aGivenSize += computedBoxSizes->size;
01333 
01334    // }
01335 
01336     boxSizes         = boxSizes->next;
01337     computedBoxSizes = computedBoxSizes->next;
01338   }
01339 }
01340 
01341 
01342 NS_IMETHODIMP
01343 nsSprocketLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
01344 {
01345    PRBool isHorizontal = IsHorizontal(aBox);
01346 
01347    nscoord biggestPref = 0;
01348 
01349    aSize.width = 0;
01350    aSize.height = 0;
01351 
01352    // run through all the children and get there min, max, and preferred sizes
01353    // return us the size of the box
01354 
01355    nsIBox* child = nsnull;
01356    aBox->GetChildBox(&child);
01357 
01358    nsFrameState frameState = 0;
01359    GetFrameState(aBox, frameState);
01360    PRBool isEqual = frameState & NS_STATE_EQUAL_SIZE;
01361    PRInt32 count = 0;
01362    
01363    while (child) 
01364    {  
01365       // ignore collapsed children
01366       PRBool isCollapsed = PR_FALSE;
01367       child->IsCollapsed(aState, isCollapsed);
01368 
01369       if (!isCollapsed)
01370       {
01371         nsSize pref(0,0);
01372         child->GetPrefSize(aState, pref);
01373         AddMargin(child, pref);
01374 
01375         if (isEqual) {
01376           if (isHorizontal)
01377           {
01378             if (pref.width > biggestPref)
01379               biggestPref = pref.width;
01380           } else {
01381             if (pref.height > biggestPref)
01382               biggestPref = pref.height;
01383           }
01384         }
01385 
01386         AddLargestSize(aSize, pref, isHorizontal);
01387         count++;
01388       }
01389 
01390       child->GetNextBox(&child);
01391    }
01392 
01393    if (isEqual) {
01394       if (isHorizontal)
01395          aSize.width = biggestPref*count;
01396       else
01397          aSize.height = biggestPref*count;
01398    }
01399     
01400    // now add our border and padding and insets
01401    AddBorderAndPadding(aBox, aSize);
01402    AddInset(aBox, aSize);
01403 
01404   return NS_OK;
01405 }
01406 
01407 NS_IMETHODIMP
01408 nsSprocketLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
01409 {
01410    PRBool isHorizontal = IsHorizontal(aBox);
01411 
01412    nscoord biggestMin = 0;
01413 
01414    aSize.width = 0;
01415    aSize.height = 0;
01416 
01417    // run through all the children and get there min, max, and preferred sizes
01418    // return us the size of the box
01419 
01420    nsIBox* child = nsnull;
01421    aBox->GetChildBox(&child);
01422    nsFrameState frameState = 0;
01423    GetFrameState(aBox, frameState);
01424    PRBool isEqual = frameState & NS_STATE_EQUAL_SIZE;
01425    PRInt32 count = 0;
01426 
01427    while (child) 
01428    {  
01429        // ignore collapsed children
01430       PRBool isCollapsed = PR_FALSE;
01431       aBox->IsCollapsed(aState, isCollapsed);
01432 
01433       if (!isCollapsed)
01434       {
01435         nsSize min(0,0);
01436         nsSize pref(0,0);
01437         nscoord flex = 0;
01438 
01439         child->GetMinSize(aState, min);        
01440         child->GetFlex(aState, flex);
01441         
01442         // if the child is not flexible then
01443         // its min size is its pref size.
01444         if (flex == 0)  {
01445             child->GetPrefSize(aState, pref);
01446             if (isHorizontal)
01447                min.width = pref.width;
01448             else
01449                min.height = pref.height;
01450         }
01451 
01452         if (isEqual) {
01453           if (isHorizontal)
01454           {
01455             if (min.width > biggestMin)
01456               biggestMin = min.width;
01457           } else {
01458             if (min.height > biggestMin)
01459               biggestMin = min.height;
01460           }
01461         }
01462 
01463         AddMargin(child, min);
01464         AddLargestSize(aSize, min, isHorizontal);
01465         count++;
01466       }
01467 
01468       child->GetNextBox(&child);
01469    }
01470 
01471    
01472    if (isEqual) {
01473       if (isHorizontal)
01474          aSize.width = biggestMin*count;
01475       else
01476          aSize.height = biggestMin*count;
01477    }
01478 
01479 // now add our border and padding and insets
01480    AddBorderAndPadding(aBox, aSize);
01481    AddInset(aBox,aSize);
01482 
01483   return NS_OK;
01484 }
01485 
01486 NS_IMETHODIMP
01487 nsSprocketLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
01488 {
01489 
01490   PRBool isHorizontal = IsHorizontal(aBox);
01491 
01492    nscoord smallestMax = NS_INTRINSICSIZE;
01493 
01494    aSize.width = NS_INTRINSICSIZE;
01495    aSize.height = NS_INTRINSICSIZE;
01496 
01497    // run through all the children and get there min, max, and preferred sizes
01498    // return us the size of the box
01499 
01500 
01501    nsIBox* child = nsnull;
01502    aBox->GetChildBox(&child);
01503    nsFrameState frameState = 0;
01504    GetFrameState(aBox, frameState);
01505    PRBool isEqual = frameState & NS_STATE_EQUAL_SIZE;
01506    PRInt32 count = 0;
01507 
01508    while (child) 
01509    {  
01510       // ignore collapsed children
01511       PRBool isCollapsed = PR_FALSE;
01512       aBox->IsCollapsed(aState, isCollapsed);
01513 
01514       if (!isCollapsed)
01515       {
01516         // if completely redefined don't even ask our child for its size.
01517         nsSize max(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
01518         nsSize min(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
01519         child->GetMaxSize(aState, max);
01520         child->GetMinSize(aState, min);
01521         nsBox::BoundsCheckMinMax(min, max);
01522 
01523         AddMargin(child, max);
01524         AddSmallestSize(aSize, max, isHorizontal);
01525 
01526         if (isEqual) {
01527           if (isHorizontal)
01528           {
01529             if (max.width < smallestMax)
01530               smallestMax = max.width;
01531           } else {
01532             if (max.height < smallestMax)
01533               smallestMax = max.height;
01534           }
01535         }
01536         count++;
01537       }
01538 
01539       child->GetNextBox(&child);  
01540    }
01541 
01542    if (isEqual) {
01543      if (isHorizontal) {
01544          if (smallestMax != NS_INTRINSICSIZE)
01545             aSize.width = smallestMax*count;
01546          else
01547             aSize.width = NS_INTRINSICSIZE;
01548      } else {
01549          if (smallestMax != NS_INTRINSICSIZE)
01550             aSize.height = smallestMax*count;
01551          else
01552             aSize.height = NS_INTRINSICSIZE;
01553      }
01554    }
01555 
01556    // now add our border and padding and insets
01557    AddBorderAndPadding(aBox, aSize);
01558    AddInset(aBox, aSize);
01559 
01560   return NS_OK;
01561 }
01562 
01563 
01564 NS_IMETHODIMP
01565 nsSprocketLayout::GetAscent(nsIBox* aBox, nsBoxLayoutState& aState, nscoord& aAscent)
01566 {
01567 
01568   PRBool isHorizontal = IsHorizontal(aBox);
01569 
01570    aAscent = 0;
01571 
01572    // run through all the children and get there min, max, and preferred sizes
01573    // return us the size of the box
01574    
01575    nsIBox* child = nsnull;
01576    aBox->GetChildBox(&child);
01577    
01578    while (child) 
01579    {  
01580       // ignore collapsed children
01581       //PRBool isCollapsed = PR_FALSE;
01582       //aBox->IsCollapsed(aState, isCollapsed);
01583 
01584       //if (!isCollapsed)
01585       //{
01586         // if completely redefined don't even ask our child for its size.
01587         nscoord ascent = 0;
01588         child->GetAscent(aState, ascent);
01589 
01590         nsMargin margin;
01591         child->GetMargin(margin);
01592         ascent += margin.top;
01593 
01594         if (isHorizontal)
01595         {
01596           if (ascent > aAscent)
01597             aAscent = ascent;
01598         } else {
01599           if (aAscent == 0)
01600             aAscent = ascent;
01601         }
01602       //}
01603       child->GetNextBox(&child);
01604       
01605    }
01606 
01607   return NS_OK;
01608 }
01609 
01610 NS_IMETHODIMP
01611 nsSprocketLayout::GetFlex(nsIBox* aBox, nsBoxLayoutState& aState, nscoord& aFlex)
01612 {
01613   return aBox->GetFlex(aState, aFlex);
01614 }
01615 
01616 
01617 NS_IMETHODIMP
01618 nsSprocketLayout::IsCollapsed(nsIBox* aBox, nsBoxLayoutState& aState, PRBool& aIsCollapsed)
01619 {
01620   return aBox->IsCollapsed(aState, aIsCollapsed);
01621 }
01622 
01623 void
01624 nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2, PRBool aIsHorizontal)
01625 {
01626   if (aIsHorizontal)
01627   {
01628     if (aSize1.height < aSize2.height)
01629        aSize1.height = aSize2.height;
01630   } else {
01631     if (aSize1.width < aSize2.width)
01632        aSize1.width = aSize2.width;
01633   }
01634 }
01635 
01636 void
01637 nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2, PRBool aIsHorizontal)
01638 {
01639   if (aIsHorizontal)
01640   {
01641     if (aSize1.height > aSize2.height)
01642        aSize1.height = aSize2.height;
01643   } else {
01644     if (aSize1.width > aSize2.width)
01645        aSize1.width = aSize2.width;
01646 
01647   }
01648 }
01649 
01650 void
01651 nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd, PRBool aIsHorizontal)
01652 {
01653   if (aIsHorizontal)
01654     AddCoord(aSize.width, aSizeToAdd.width);
01655   else
01656     AddCoord(aSize.height, aSizeToAdd.height);
01657 
01658   SetLargestSize(aSize, aSizeToAdd, aIsHorizontal);
01659 }
01660 
01661 void
01662 nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd)
01663 {
01664   if (aCoord != NS_INTRINSICSIZE) 
01665   {
01666     if (aCoordToAdd == NS_INTRINSICSIZE)
01667       aCoord = aCoordToAdd;
01668     else
01669       aCoord += aCoordToAdd;
01670   }
01671 }
01672 void
01673 nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd, PRBool aIsHorizontal)
01674 {
01675   if (aIsHorizontal)
01676     AddCoord(aSize.width, aSizeToAdd.width);
01677   else
01678     AddCoord(aSize.height, aSizeToAdd.height);
01679     
01680   SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal);
01681 }
01682 
01683 PRBool
01684 nsSprocketLayout::GetDefaultFlex(PRInt32& aFlex)
01685 {
01686     aFlex = 0;
01687     return PR_TRUE;
01688 }
01689 
01690 void
01691 nsBoxSize::Add(const nsSize& minSize, 
01692                const nsSize& prefSize,
01693                const nsSize& maxSize,
01694                nscoord aAscent,
01695                nscoord aFlex,
01696                PRBool aIsHorizontal)
01697 {
01698   nscoord pref2;
01699   nscoord min2;
01700   nscoord max2;
01701 
01702   if (aIsHorizontal) {
01703     pref2 = prefSize.width;
01704     min2  = minSize.width;
01705     max2  = maxSize.width;
01706   } else {
01707     pref2 = prefSize.height;
01708     min2  = minSize.height;
01709     max2  = maxSize.height;
01710   }
01711 
01712   if (min2 > min)
01713     min = min2;
01714 
01715   if (pref2 > pref)
01716     pref = pref2;
01717 
01718   if (max2 < max)
01719     max = max2;
01720 
01721   flex = aFlex;
01722 
01723   if (!aIsHorizontal) {
01724     if (aAscent > ascent)
01725       ascent = aAscent;
01726     }
01727 }
01728 
01729 void
01730 nsBoxSize::Add(const nsMargin& aMargin, PRBool aIsHorizontal)
01731 {
01732   if (aIsHorizontal) {
01733     left  += aMargin.left;
01734     right += aMargin.right;
01735     pref -= (aMargin.left + aMargin.right);
01736   } else {
01737     left  += aMargin.top;
01738     right += aMargin.bottom;
01739     pref -= (aMargin.top + aMargin.bottom);
01740   }
01741 
01742   if (pref < min)
01743      min = pref;
01744 }
01745 
01746 nsComputedBoxSize::nsComputedBoxSize()
01747 {
01748   Clear();
01749 }
01750 
01751 void
01752 nsComputedBoxSize::Clear()
01753 {
01754   resized = PR_FALSE;
01755   valid = PR_FALSE;
01756   size = 0;
01757   next = nsnull;
01758 }
01759 
01760 nsBoxSize::nsBoxSize()
01761 {
01762   Clear();
01763 }
01764 
01765 void
01766 nsBoxSize::Clear()
01767 {
01768   pref = 0;
01769   min = 0;
01770   max = NS_INTRINSICSIZE;
01771   collapsed = PR_FALSE;
01772   ascent = 0;
01773   left = 0;
01774   right = 0;
01775   flex = 0;
01776   next = nsnull;
01777   bogus = PR_FALSE;
01778 }
01779 
01780 
01781 void* 
01782 nsBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
01783 {
01784    void* mem = 0;
01785    aState.AllocateStackMemory(sz,&mem);
01786    return mem;
01787 }
01788 
01789 
01790 void 
01791 nsBoxSize::operator delete(void* aPtr, size_t sz)
01792 {
01793 }
01794 
01795 
01796 void* 
01797 nsComputedBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
01798 {
01799   
01800    void* mem = 0;
01801    aState.AllocateStackMemory(sz,&mem);
01802    return mem;
01803 }
01804 
01805 void 
01806 nsComputedBoxSize::operator delete(void* aPtr, size_t sz)
01807 {
01808 }