LCOV - code coverage report
Current view: top level - layout/xul - nsSprocketLayout.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 523 749 69.8 %
Date: 2017-07-14 16:53:18 Functions: 26 30 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : //
       7             : // Eric Vaughan
       8             : // Netscape Communications
       9             : //
      10             : // See documentation in associated header file
      11             : //
      12             : 
      13             : #include "nsBoxLayoutState.h"
      14             : #include "nsSprocketLayout.h"
      15             : #include "nsPresContext.h"
      16             : #include "nsCOMPtr.h"
      17             : #include "nsIContent.h"
      18             : #include "nsIPresShell.h"
      19             : #include "nsContainerFrame.h"
      20             : #include "nsBoxFrame.h"
      21             : #include "StackArena.h"
      22             : #include "mozilla/Likely.h"
      23             : #include <algorithm>
      24             : 
      25             : nsBoxLayout* nsSprocketLayout::gInstance = nullptr;
      26             : 
      27             : //#define DEBUG_GROW
      28             : 
      29             : #define DEBUG_SPRING_SIZE 8
      30             : #define DEBUG_BORDER_SIZE 2
      31             : #define COIL_SIZE 8
      32             : 
      33             : 
      34             : nsresult
      35         232 : NS_NewSprocketLayout(nsCOMPtr<nsBoxLayout>& aNewLayout)
      36             : {
      37         232 :   if (!nsSprocketLayout::gInstance) {
      38           2 :     nsSprocketLayout::gInstance = new nsSprocketLayout();
      39           2 :     NS_IF_ADDREF(nsSprocketLayout::gInstance);
      40             :   }
      41             :   // we have not instance variables so just return our static one.
      42         232 :   aNewLayout = nsSprocketLayout::gInstance;
      43         232 :   return NS_OK;
      44             : }
      45             : 
      46             : /*static*/ void
      47           0 : nsSprocketLayout::Shutdown()
      48             : {
      49           0 :   NS_IF_RELEASE(gInstance);
      50           0 : }
      51             : 
      52           2 : nsSprocketLayout::nsSprocketLayout()
      53             : {
      54           2 : }
      55             : 
      56             : bool
      57        4031 : nsSprocketLayout::IsXULHorizontal(nsIFrame* aBox)
      58             : {
      59        4031 :    return (aBox->GetStateBits() & NS_STATE_IS_HORIZONTAL) != 0;
      60             : }
      61             : 
      62             : void
      63        3116 : nsSprocketLayout::GetFrameState(nsIFrame* aBox, nsFrameState& aState)
      64             : {
      65        3116 :    aState = aBox->GetStateBits();
      66        3116 : }
      67             : 
      68             : static uint8_t
      69        1249 : GetFrameDirection(nsIFrame* aBox)
      70             : {
      71        1249 :    return aBox->StyleVisibility()->mDirection;
      72             : }
      73             : 
      74             : static void
      75         876 : HandleBoxPack(nsIFrame* aBox, const nsFrameState& aFrameState, nscoord& aX, nscoord& aY,
      76             :               const nsRect& aOriginalRect, const nsRect& aClientRect)
      77             : {
      78             :   // In the normal direction we lay out our kids in the positive direction (e.g., |x| will get
      79             :   // bigger for a horizontal box, and |y| will get bigger for a vertical box).  In the reverse
      80             :   // direction, the opposite is true.  We'll be laying out each child at a smaller |x| or
      81             :   // |y|.
      82         876 :   uint8_t frameDirection = GetFrameDirection(aBox);
      83             : 
      84         876 :   if (aFrameState & NS_STATE_IS_HORIZONTAL) {
      85         666 :     if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
      86             :       // The normal direction. |x| increases as we move through our children.
      87         666 :       aX = aClientRect.x;
      88             :     }
      89             :     else {
      90             :       // The reverse direction. |x| decreases as we move through our children.
      91           0 :       aX = aClientRect.x + aOriginalRect.width;
      92             :     }
      93             :     // |y| is always in the normal direction in horizontal boxes
      94         666 :     aY = aClientRect.y;
      95             :   }
      96             :   else {
      97             :     // take direction property into account for |x| in vertical boxes
      98         210 :     if (frameDirection == NS_STYLE_DIRECTION_LTR) {
      99             :       // The normal direction. |x| increases as we move through our children.
     100         210 :       aX = aClientRect.x;
     101             :     }
     102             :     else {
     103             :       // The reverse direction. |x| decreases as we move through our children.
     104           0 :       aX = aClientRect.x + aOriginalRect.width;
     105             :     }
     106         210 :     if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
     107             :       // The normal direction. |y| increases as we move through our children.
     108         210 :       aY = aClientRect.y;
     109             :     }
     110             :     else {
     111             :       // The reverse direction. |y| decreases as we move through our children.
     112           0 :       aY = aClientRect.y + aOriginalRect.height;
     113             :     }
     114             :   }
     115             : 
     116             :   // Get our pack/alignment information.
     117         876 :   nsIFrame::Halignment halign = aBox->GetXULHAlign();
     118         876 :   nsIFrame::Valignment valign = aBox->GetXULVAlign();
     119             : 
     120             :   // The following code handles box PACKING.  Packing comes into play in the case where the computed size for
     121             :   // all of our children (now stored in our client rect) is smaller than the size available for
     122             :   // the box (stored in |aOriginalRect|).
     123             :   //
     124             :   // Here we adjust our |x| and |y| variables accordingly so that we start at the beginning,
     125             :   // middle, or end of the box.
     126             :   //
     127             :   // XXXdwh JUSTIFY needs to be implemented!
     128         876 :   if (aFrameState & NS_STATE_IS_HORIZONTAL) {
     129         666 :     switch(halign) {
     130             :       case nsBoxFrame::hAlign_Left:
     131         566 :         break; // Nothing to do.  The default initialized us properly.
     132             : 
     133             :       case nsBoxFrame::hAlign_Center:
     134         100 :         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
     135         100 :           aX += (aOriginalRect.width - aClientRect.width)/2;
     136             :         else
     137           0 :           aX -= (aOriginalRect.width - aClientRect.width)/2;
     138         100 :         break;
     139             : 
     140             :       case nsBoxFrame::hAlign_Right:
     141           0 :         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
     142           0 :           aX += (aOriginalRect.width - aClientRect.width);
     143             :         else
     144           0 :           aX -= (aOriginalRect.width - aClientRect.width);
     145           0 :         break; // Nothing to do for the reverse dir.  The default initialized us properly.
     146             :     }
     147             :   } else {
     148         210 :     switch(valign) {
     149             :       case nsBoxFrame::vAlign_Top:
     150             :       case nsBoxFrame::vAlign_BaseLine: // This value is technically impossible to specify for pack.
     151         204 :         break;  // Don't do anything.  We were initialized correctly.
     152             : 
     153             :       case nsBoxFrame::vAlign_Middle:
     154           6 :         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
     155           6 :           aY += (aOriginalRect.height - aClientRect.height)/2;
     156             :         else
     157           0 :           aY -= (aOriginalRect.height - aClientRect.height)/2;
     158           6 :         break;
     159             : 
     160             :       case nsBoxFrame::vAlign_Bottom:
     161           0 :         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
     162           0 :           aY += (aOriginalRect.height - aClientRect.height);
     163             :         else
     164           0 :           aY -= (aOriginalRect.height - aClientRect.height);
     165           0 :         break;
     166             :     }
     167             :   }
     168         876 : }
     169             : 
     170             : NS_IMETHODIMP
     171         515 : nsSprocketLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState)
     172             : {
     173             :   // See if we are collapsed. If we are, then simply iterate over all our
     174             :   // children and give them a rect of 0 width and height.
     175         515 :   if (aBox->IsXULCollapsed()) {
     176          77 :     nsIFrame* child = nsBox::GetChildXULBox(aBox);
     177         321 :     while(child)
     178             :     {
     179         122 :       nsBoxFrame::LayoutChildAt(aState, child, nsRect(0,0,0,0));
     180         122 :       child = nsBox::GetNextXULBox(child);
     181             :     }
     182          77 :     return NS_OK;
     183             :   }
     184             : 
     185         876 :   nsBoxLayoutState::AutoReflowDepth depth(aState);
     186         876 :   mozilla::AutoStackArena arena;
     187             : 
     188             :   // ----- figure out our size ----------
     189         438 :   const nsSize originalSize = aBox->GetSize();
     190             : 
     191             :   // -- make sure we remove our border and padding  ----
     192         876 :   nsRect clientRect;
     193         438 :   aBox->GetXULClientRect(clientRect);
     194             : 
     195             :   // |originalClientRect| represents the rect of the entire box (excluding borders
     196             :   // and padding).  We store it here because we're going to use |clientRect| to hold
     197             :   // the required size for all our kids.  As an example, consider an hbox with a
     198             :   // specified width of 300.  If the kids total only 150 pixels of width, then
     199             :   // we have 150 pixels left over.  |clientRect| is going to hold a width of 150 and
     200             :   // is going to be adjusted based off the value of the PACK property.  If flexible
     201             :   // objects are in the box, then the two rects will match.
     202         876 :   nsRect originalClientRect(clientRect);
     203             : 
     204             :   // The frame state contains cached knowledge about our box, such as our orientation
     205             :   // and direction.
     206         438 :   nsFrameState frameState = nsFrameState(0);
     207         438 :   GetFrameState(aBox, frameState);
     208             : 
     209             :   // Build a list of our children's desired sizes and computed sizes
     210         438 :   nsBoxSize*         boxSizes = nullptr;
     211         438 :   nsComputedBoxSize* computedBoxSizes = nullptr;
     212             : 
     213         438 :   nscoord min = 0;
     214         438 :   nscoord max = 0;
     215         438 :   int32_t flexes = 0;
     216         438 :   PopulateBoxSizes(aBox, aState, boxSizes, min, max, flexes);
     217             : 
     218             :   // The |size| variable will hold the total size of children along the axis of
     219             :   // the box.  Continuing with the example begun in the comment above, size would
     220             :   // be 150 pixels.
     221         438 :   nscoord size = clientRect.width;
     222         438 :   if (!IsXULHorizontal(aBox))
     223         105 :     size = clientRect.height;
     224         438 :   ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes);
     225             : 
     226             :   // After the call to ComputeChildSizes, the |size| variable contains the
     227             :   // total required size of all the children.  We adjust our clientRect in the
     228             :   // appropriate dimension to match this size.  In our example, we now assign
     229             :   // 150 pixels into the clientRect.width.
     230             :   //
     231             :   // The variables |min| and |max| hold the minimum required size box must be
     232             :   // in the OPPOSITE orientation, e.g., for a horizontal box, |min| is the minimum
     233             :   // height we require to enclose our children, and |max| is the maximum height
     234             :   // required to enclose our children.
     235         438 :   if (IsXULHorizontal(aBox)) {
     236         333 :     clientRect.width = size;
     237         333 :     if (clientRect.height < min)
     238           5 :       clientRect.height = min;
     239             : 
     240         333 :     if (frameState & NS_STATE_AUTO_STRETCH) {
     241         215 :       if (clientRect.height > max)
     242           0 :         clientRect.height = max;
     243             :     }
     244             :   } else {
     245         105 :     clientRect.height = size;
     246         105 :     if (clientRect.width < min)
     247           5 :       clientRect.width = min;
     248             : 
     249         105 :     if (frameState & NS_STATE_AUTO_STRETCH) {
     250         100 :       if (clientRect.width > max)
     251           0 :         clientRect.width = max;
     252             :     }
     253             :   }
     254             : 
     255             :   // With the sizes computed, now it's time to lay out our children.
     256             :   bool finished;
     257         438 :   nscoord passes = 0;
     258             : 
     259             :   // We flow children at their preferred locations (along with the appropriate computed flex).
     260             :   // After we flow a child, it is possible that the child will change its size.  If/when this happens,
     261             :   // we have to do another pass.  Typically only 2 passes are required, but the code is prepared to
     262             :   // do as many passes as are necessary to achieve equilibrium.
     263         438 :   nscoord x = 0;
     264         438 :   nscoord y = 0;
     265         438 :   nscoord origX = 0;
     266         438 :   nscoord origY = 0;
     267             : 
     268             :   // |childResized| lets us know if a child changed its size after we attempted to lay it out at
     269             :   // the specified size.  If this happens, we usually have to do another pass.
     270         438 :   bool childResized = false;
     271             : 
     272             :   // |passes| stores our number of passes.  If for any reason we end up doing more than, say, 10
     273             :   // passes, we assert to indicate that something is seriously screwed up.
     274         438 :   passes = 0;
     275           0 :   do
     276             :   {
     277             : #ifdef DEBUG_REFLOW
     278             :     if (passes > 0) {
     279             :       AddIndents();
     280             :       printf("ChildResized doing pass: %d\n", passes);
     281             :     }
     282             : #endif
     283             : 
     284             :     // Always assume that we're done.  This will change if, for example, children don't stay
     285             :     // the same size after being flowed.
     286         438 :     finished = true;
     287             : 
     288             :     // Handle box packing.
     289         438 :     HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
     290             : 
     291             :     // Now that packing is taken care of we set up a few additional
     292             :     // tracking variables.
     293         438 :     origX = x;
     294         438 :     origY = y;
     295             : 
     296             :     // Now we iterate over our box children and our box size lists in
     297             :     // parallel.  For each child, we look at its sizes and figure out
     298             :     // where to place it.
     299         438 :     nsComputedBoxSize* childComputedBoxSize = computedBoxSizes;
     300         438 :     nsBoxSize* childBoxSize                 = boxSizes;
     301             : 
     302         438 :     nsIFrame* child = nsBox::GetChildXULBox(aBox);
     303             : 
     304         438 :     int32_t count = 0;
     305        2784 :     while (child || (childBoxSize && childBoxSize->bogus))
     306             :     {
     307             :       // If for some reason, our lists are not the same length, we guard
     308             :       // by bailing out of the loop.
     309        1173 :       if (childBoxSize == nullptr) {
     310           0 :         NS_NOTREACHED("Lists not the same length.");
     311           0 :         break;
     312             :       }
     313             : 
     314        1173 :       nscoord width = clientRect.width;
     315        1173 :       nscoord height = clientRect.height;
     316             : 
     317        1173 :       if (!childBoxSize->bogus) {
     318             :         // We have a valid box size entry.  This entry already contains information about our
     319             :         // sizes along the axis of the box (e.g., widths in a horizontal box).  If our default
     320             :         // ALIGN is not stretch, however, then we also need to know the child's size along the
     321             :         // opposite axis.
     322        1173 :         if (!(frameState & NS_STATE_AUTO_STRETCH)) {
     323         222 :            nsSize prefSize = child->GetXULPrefSize(aState);
     324         222 :            nsSize minSize = child->GetXULMinSize(aState);
     325         222 :            nsSize maxSize = child->GetXULMaxSize(aState);
     326         222 :            prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize);
     327             : 
     328         222 :            AddMargin(child, prefSize);
     329         222 :            width = std::min(prefSize.width, originalClientRect.width);
     330         222 :            height = std::min(prefSize.height, originalClientRect.height);
     331             :         }
     332             :       }
     333             : 
     334             :       // Obtain the computed size along the axis of the box for this child from the computedBoxSize entry.
     335             :       // We store the result in |width| for horizontal boxes and |height| for vertical boxes.
     336        1173 :       if (frameState & NS_STATE_IS_HORIZONTAL)
     337         805 :         width = childComputedBoxSize->size;
     338             :       else
     339         368 :         height = childComputedBoxSize->size;
     340             : 
     341             :       // Adjust our x/y for the left/right spacing.
     342        1173 :       if (frameState & NS_STATE_IS_HORIZONTAL) {
     343         805 :         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
     344         805 :           x += (childBoxSize->left);
     345             :         else
     346           0 :           x -= (childBoxSize->right);
     347             :       } else {
     348         368 :         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
     349         368 :           y += (childBoxSize->left);
     350             :         else
     351           0 :           y -= (childBoxSize->right);
     352             :       }
     353             : 
     354             :       // Now we build a child rect.
     355        1173 :       nscoord rectX = x;
     356        1173 :       nscoord rectY = y;
     357        1173 :       if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
     358           0 :         if (frameState & NS_STATE_IS_HORIZONTAL)
     359           0 :           rectX -= width;
     360             :         else
     361           0 :           rectY -= height;
     362             :       }
     363             : 
     364             :       // We now create an accurate child rect based off our computed size information.
     365        2346 :       nsRect childRect(rectX, rectY, width, height);
     366             : 
     367             :       // Sanity check against our clientRect.  It is possible that a child specified
     368             :       // a size that is too large to fit.  If that happens, then we have to grow
     369             :       // our client rect.  Remember, clientRect is not the total rect of the enclosing
     370             :       // box.  It currently holds our perception of how big the children needed to
     371             :       // be.
     372        1173 :       if (childRect.width > clientRect.width)
     373           0 :         clientRect.width = childRect.width;
     374             : 
     375        1173 :       if (childRect.height > clientRect.height)
     376           0 :         clientRect.height = childRect.height;
     377             : 
     378             :       // Either |nextX| or |nextY| is updated by this function call, according
     379             :       // to our axis.
     380        1173 :       nscoord nextX = x;
     381        1173 :       nscoord nextY = y;
     382             : 
     383        1173 :       ComputeChildsNextPosition(aBox, x, y, nextX, nextY, childRect);
     384             : 
     385             :       // Now we further update our nextX/Y along our axis.
     386             :       // We also set childRect.y/x along the opposite axis appropriately for a
     387             :       // stretch alignment.  (Non-stretch alignment is handled below.)
     388        1173 :       if (frameState & NS_STATE_IS_HORIZONTAL) {
     389         805 :         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
     390         805 :           nextX += (childBoxSize->right);
     391             :         else
     392           0 :           nextX -= (childBoxSize->left);
     393         805 :         childRect.y = originalClientRect.y;
     394             :       }
     395             :       else {
     396         368 :         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
     397         368 :           nextY += (childBoxSize->right);
     398             :         else
     399           0 :           nextY -= (childBoxSize->left);
     400         368 :         if (GetFrameDirection(aBox) == NS_STYLE_DIRECTION_LTR) {
     401         368 :           childRect.x = originalClientRect.x;
     402             :         } else {
     403             :           // keep the right edge of the box the same
     404           0 :           childRect.x = clientRect.x + originalClientRect.width - childRect.width;
     405             :         }
     406             :       }
     407             : 
     408             :       // If we encounter a completely bogus box size, we just leave this child completely
     409             :       // alone and continue through the loop to the next child.
     410        1173 :       if (childBoxSize->bogus)
     411             :       {
     412           0 :         childComputedBoxSize = childComputedBoxSize->next;
     413           0 :         childBoxSize = childBoxSize->next;
     414           0 :         count++;
     415           0 :         x = nextX;
     416           0 :         y = nextY;
     417           0 :         continue;
     418             :       }
     419             : 
     420        1173 :       nsMargin margin(0,0,0,0);
     421             : 
     422        1173 :       bool layout = true;
     423             : 
     424             :       // Deflate the rect of our child by its margin.
     425        1173 :       child->GetXULMargin(margin);
     426        1173 :       childRect.Deflate(margin);
     427        1173 :       if (childRect.width < 0)
     428           0 :         childRect.width = 0;
     429        1173 :       if (childRect.height < 0)
     430           0 :         childRect.height = 0;
     431             : 
     432             :       // Now we're trying to figure out if we have to lay out this child, i.e., to call
     433             :       // the child's XULLayout method.
     434        1173 :       if (passes > 0) {
     435           0 :         layout = false;
     436             :       } else {
     437             :         // Always perform layout if we are dirty or have dirty children
     438        1173 :         if (!NS_SUBTREE_DIRTY(child))
     439         680 :           layout = false;
     440             :       }
     441             : 
     442        2346 :       nsRect oldRect(child->GetRect());
     443             : 
     444             :       // Non-stretch alignment will be handled in AlignChildren(), so don't
     445             :       // change child out-of-axis positions yet.
     446        1173 :       if (!(frameState & NS_STATE_AUTO_STRETCH)) {
     447         222 :         if (frameState & NS_STATE_IS_HORIZONTAL) {
     448         220 :           childRect.y = oldRect.y;
     449             :         } else {
     450           2 :           childRect.x = oldRect.x;
     451             :         }
     452             :       }
     453             : 
     454             :       // We computed a childRect.  Now we want to set the bounds of the child to be that rect.
     455             :       // If our old rect is different, then we know our size changed and we cache that fact
     456             :       // in the |sizeChanged| variable.
     457             : 
     458        1173 :       child->SetXULBounds(aState, childRect);
     459        2037 :       bool sizeChanged = (childRect.width != oldRect.width ||
     460        2037 :                             childRect.height != oldRect.height);
     461             : 
     462        1173 :       if (sizeChanged) {
     463             :         // Our size is different.  Sanity check against our maximum allowed size to ensure
     464             :         // we didn't exceed it.
     465         371 :         nsSize minSize = child->GetXULMinSize(aState);
     466         371 :         nsSize maxSize = child->GetXULMaxSize(aState);
     467         371 :         maxSize = nsBox::BoundsCheckMinMax(minSize, maxSize);
     468             : 
     469             :         // make sure the size is in our max size.
     470         371 :         if (childRect.width > maxSize.width)
     471           0 :           childRect.width = maxSize.width;
     472             : 
     473         371 :         if (childRect.height > maxSize.height)
     474           0 :           childRect.height = maxSize.height;
     475             : 
     476             :         // set it again
     477         371 :         child->SetXULBounds(aState, childRect);
     478             :       }
     479             : 
     480             :       // If we already determined that layout was required or if our size has changed, then
     481             :       // we make sure to call layout on the child, since its children may need to be shifted
     482             :       // around as a result of the size change.
     483        1173 :       if (layout || sizeChanged)
     484         611 :         child->XULLayout(aState);
     485             : 
     486             :       // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout.
     487             :       // We have to check for this.
     488        2346 :       nsRect newChildRect(child->GetRect());
     489             : 
     490        1173 :       if (!newChildRect.IsEqualInterior(childRect)) {
     491             : #ifdef DEBUG_GROW
     492             :         child->XULDumpBox(stdout);
     493             :         printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height);
     494             : #endif
     495           0 :         newChildRect.Inflate(margin);
     496           0 :         childRect.Inflate(margin);
     497             : 
     498             :         // The child changed size during layout.  The ChildResized method handles this
     499             :         // scenario.
     500             :         ChildResized(aBox,
     501             :                      aState,
     502             :                      child,
     503             :                      childBoxSize,
     504             :                      childComputedBoxSize,
     505             :                      boxSizes,
     506             :                      computedBoxSizes,
     507             :                      childRect,
     508             :                      newChildRect,
     509             :                      clientRect,
     510             :                      flexes,
     511           0 :                      finished);
     512             : 
     513             :         // We note that a child changed size, which means that another pass will be required.
     514           0 :         childResized = true;
     515             : 
     516             :         // Now that a child resized, it's entirely possible that OUR rect is too small.  Now we
     517             :         // ensure that |originalClientRect| is grown to accommodate the size of |clientRect|.
     518           0 :         if (clientRect.width > originalClientRect.width)
     519           0 :           originalClientRect.width = clientRect.width;
     520             : 
     521           0 :         if (clientRect.height > originalClientRect.height)
     522           0 :           originalClientRect.height = clientRect.height;
     523             : 
     524           0 :         if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
     525             :           // Our childRect had its XMost() or YMost() (depending on our layout
     526             :           // direction), positioned at a certain point.  Ensure that the
     527             :           // newChildRect satisfies the same constraint.  Note that this is
     528             :           // just equivalent to adjusting the x/y by the difference in
     529             :           // width/height between childRect and newChildRect.  So we don't need
     530             :           // to reaccount for the left and right of the box layout state again.
     531           0 :           if (frameState & NS_STATE_IS_HORIZONTAL)
     532           0 :             newChildRect.x = childRect.XMost() - newChildRect.width;
     533             :           else
     534           0 :             newChildRect.y = childRect.YMost() - newChildRect.height;
     535             :         }
     536             : 
     537           0 :         if (!(frameState & NS_STATE_IS_HORIZONTAL)) {
     538           0 :           if (GetFrameDirection(aBox) != NS_STYLE_DIRECTION_LTR) {
     539             :             // keep the right edge the same
     540           0 :             newChildRect.x = childRect.XMost() - newChildRect.width;
     541             :           }
     542             :         }
     543             : 
     544             :         // If the child resized then recompute its position.
     545           0 :         ComputeChildsNextPosition(aBox, x, y, nextX, nextY, newChildRect);
     546             : 
     547           0 :         if (newChildRect.width >= margin.left + margin.right && newChildRect.height >= margin.top + margin.bottom)
     548           0 :           newChildRect.Deflate(margin);
     549             : 
     550           0 :         if (childRect.width >= margin.left + margin.right && childRect.height >= margin.top + margin.bottom)
     551           0 :           childRect.Deflate(margin);
     552             : 
     553           0 :         child->SetXULBounds(aState, newChildRect);
     554             : 
     555             :         // If we are the first box that changed size, then we don't need to do a second pass
     556           0 :         if (count == 0)
     557           0 :           finished = true;
     558             :       }
     559             : 
     560             :       // Now update our x/y finally.
     561        1173 :       x = nextX;
     562        1173 :       y = nextY;
     563             : 
     564             :       // Move to the next child.
     565        1173 :       childComputedBoxSize = childComputedBoxSize->next;
     566        1173 :       childBoxSize = childBoxSize->next;
     567             : 
     568        1173 :       child = nsBox::GetNextXULBox(child);
     569        1173 :       count++;
     570             :     }
     571             : 
     572             :     // Sanity-checking code to ensure we don't do an infinite # of passes.
     573         438 :     passes++;
     574         438 :     NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!");
     575         438 :     if (passes >= 10)
     576           0 :       break;
     577         438 :   } while (false == finished);
     578             : 
     579             :   // Get rid of our size lists.
     580        1173 :   while(boxSizes)
     581             :   {
     582        1173 :     nsBoxSize* toDelete = boxSizes;
     583        1173 :     boxSizes = boxSizes->next;
     584        1173 :     delete toDelete;
     585             :   }
     586             : 
     587        1198 :   while(computedBoxSizes)
     588             :   {
     589        1198 :     nsComputedBoxSize* toDelete = computedBoxSizes;
     590        1198 :     computedBoxSizes = computedBoxSizes->next;
     591        1198 :     delete toDelete;
     592             :   }
     593             : 
     594         438 :   if (childResized) {
     595             :     // See if one of our children forced us to get bigger
     596           0 :     nsRect tmpClientRect(originalClientRect);
     597           0 :     nsMargin bp(0,0,0,0);
     598           0 :     aBox->GetXULBorderAndPadding(bp);
     599           0 :     tmpClientRect.Inflate(bp);
     600             : 
     601           0 :     if (tmpClientRect.width > originalSize.width || tmpClientRect.height > originalSize.height)
     602             :     {
     603             :       // if it did reset our bounds.
     604           0 :       nsRect bounds(aBox->GetRect());
     605           0 :       if (tmpClientRect.width > originalSize.width)
     606           0 :         bounds.width = tmpClientRect.width;
     607             : 
     608           0 :       if (tmpClientRect.height > originalSize.height)
     609           0 :         bounds.height = tmpClientRect.height;
     610             : 
     611           0 :       aBox->SetXULBounds(aState, bounds);
     612             :     }
     613             :   }
     614             : 
     615             :   // Because our size grew, we now have to readjust because of box packing.  Repack
     616             :   // in order to update our x and y to the correct values.
     617         438 :   HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
     618             : 
     619             :   // Compare against our original x and y and only worry about adjusting the children if
     620             :   // we really did have to change the positions because of packing (typically for 'center'
     621             :   // or 'end' pack values).
     622         438 :   if (x != origX || y != origY) {
     623           0 :     nsIFrame* child = nsBox::GetChildXULBox(aBox);
     624             : 
     625             :     // reposition all our children
     626           0 :     while (child)
     627             :     {
     628           0 :       nsRect childRect(child->GetRect());
     629           0 :       childRect.x += (x - origX);
     630           0 :       childRect.y += (y - origY);
     631           0 :       child->SetXULBounds(aState, childRect);
     632           0 :       child = nsBox::GetNextXULBox(child);
     633             :     }
     634             :   }
     635             : 
     636             :   // Perform out-of-axis alignment for non-stretch alignments
     637         438 :   if (!(frameState & NS_STATE_AUTO_STRETCH)) {
     638         123 :     AlignChildren(aBox, aState);
     639             :   }
     640             : 
     641             :   // That's it!  If you made it this far without having a nervous breakdown,
     642             :   // congratulations!  Go get yourself a beer.
     643         438 :   return NS_OK;
     644             : }
     645             : 
     646             : void
     647         438 : nsSprocketLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes)
     648             : {
     649             :   // used for the equal size flag
     650         438 :   nscoord biggestPrefWidth = 0;
     651         438 :   nscoord biggestMinWidth = 0;
     652         438 :   nscoord smallestMaxWidth = NS_INTRINSICSIZE;
     653             : 
     654         438 :   nsFrameState frameState = nsFrameState(0);
     655         438 :   GetFrameState(aBox, frameState);
     656             : 
     657             :   //if (frameState & NS_STATE_CURRENTLY_IN_DEBUG)
     658             :   //   printf("In debug\n");
     659             : 
     660         438 :   aMinSize = 0;
     661         438 :   aMaxSize = NS_INTRINSICSIZE;
     662             : 
     663             :   bool isHorizontal;
     664             : 
     665         438 :   if (IsXULHorizontal(aBox))
     666         333 :      isHorizontal = true;
     667             :   else
     668         105 :      isHorizontal = false;
     669             : 
     670             :   // this is a nice little optimization
     671             :   // it turns out that if we only have 1 flexable child
     672             :   // then it does not matter what its preferred size is
     673             :   // there is nothing to flex it relative. This is great
     674             :   // because we can avoid asking for a preferred size in this
     675             :   // case. Why is this good? Well you might have html inside it
     676             :   // and asking html for its preferred size is rather expensive.
     677             :   // so we can just optimize it out this way.
     678             : 
     679             :   // set flexes
     680         438 :   nsIFrame* child = nsBox::GetChildXULBox(aBox);
     681             : 
     682         438 :   aFlexes = 0;
     683         438 :   nsBoxSize* currentBox = nullptr;
     684             : 
     685             : #if 0
     686             :   nsBoxSize* start = aBoxSizes;
     687             : 
     688             :   while(child)
     689             :   {
     690             :     // ok if we started with a list move down the list
     691             :     // until we reach the end. Then start looking at childen.
     692             :     // This feature is used extensively for Grid.
     693             :     nscoord flex = 0;
     694             : 
     695             :     if (!start) {
     696             :       if (!currentBox) {
     697             :         aBoxSizes      = new (aState) nsBoxSize();
     698             :         currentBox      = aBoxSizes;
     699             :       } else {
     700             :         currentBox->next      = new (aState) nsBoxSize();
     701             :         currentBox      = currentBox->next;
     702             :       }
     703             : 
     704             : 
     705             :       flex = child->GetXULFlex();
     706             : 
     707             :       currentBox->flex = flex;
     708             :       currentBox->collapsed = child->IsXULCollapsed();
     709             :     } else {
     710             :       flex = start->flex;
     711             :       start = start->next;
     712             :     }
     713             : 
     714             :     if (flex > 0)
     715             :        aFlexes++;
     716             : 
     717             :     child = GetNextXULBox(child);
     718             :   }
     719             : #endif
     720             : 
     721             :   // get pref, min, max
     722         438 :   child = nsBox::GetChildXULBox(aBox);
     723         438 :   currentBox = aBoxSizes;
     724         438 :   nsBoxSize* last = nullptr;
     725             : 
     726         438 :   nscoord maxFlex = 0;
     727         438 :   int32_t childCount = 0;
     728             : 
     729        2784 :   while(child)
     730             :   {
     731        1173 :     while (currentBox && currentBox->bogus) {
     732           0 :       last = currentBox;
     733           0 :       currentBox = currentBox->next;
     734             :     }
     735        1173 :     ++childCount;
     736        1173 :     nsSize pref(0,0);
     737        1173 :     nsSize minSize(0,0);
     738        1173 :     nsSize maxSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
     739        1173 :     nscoord ascent = 0;
     740        1173 :     bool collapsed = child->IsXULCollapsed();
     741             : 
     742        1173 :     if (!collapsed) {
     743             :     // only one flexible child? Cool we will just make its preferred size
     744             :     // 0 then and not even have to ask for it.
     745             :     //if (flexes != 1)  {
     746             : 
     747        1008 :       pref = child->GetXULPrefSize(aState);
     748        1008 :       minSize = child->GetXULMinSize(aState);
     749        1008 :       maxSize = nsBox::BoundsCheckMinMax(minSize, child->GetXULMaxSize(aState));
     750        1008 :       ascent = child->GetXULBoxAscent(aState);
     751        1008 :       nsMargin margin;
     752        1008 :       child->GetXULMargin(margin);
     753        1008 :       ascent += margin.top;
     754             :     //}
     755             : 
     756        1008 :       pref = nsBox::BoundsCheck(minSize, pref, maxSize);
     757             : 
     758        1008 :       AddMargin(child, pref);
     759        1008 :       AddMargin(child, minSize);
     760        1008 :       AddMargin(child, maxSize);
     761             :     }
     762             : 
     763        1173 :     if (!currentBox) {
     764             :       // create one.
     765        1173 :       currentBox = new (aState) nsBoxSize();
     766        1173 :       if (!aBoxSizes) {
     767         413 :         aBoxSizes = currentBox;
     768         413 :         last = aBoxSizes;
     769             :       } else {
     770         760 :         last->next = currentBox;
     771         760 :         last = currentBox;
     772             :       }
     773             : 
     774             :       nscoord minWidth;
     775             :       nscoord maxWidth;
     776             :       nscoord prefWidth;
     777             : 
     778             :       // get sizes from child
     779        1173 :       if (isHorizontal) {
     780         805 :           minWidth  = minSize.width;
     781         805 :           maxWidth  = maxSize.width;
     782         805 :           prefWidth = pref.width;
     783             :       } else {
     784         368 :           minWidth = minSize.height;
     785         368 :           maxWidth = maxSize.height;
     786         368 :           prefWidth = pref.height;
     787             :       }
     788             : 
     789        1173 :       nscoord flex = child->GetXULFlex();
     790             : 
     791             :       // set them if you collapsed you are not flexible.
     792        1173 :       if (collapsed) {
     793         165 :         currentBox->flex = 0;
     794             :       }
     795             :       else {
     796        1008 :         if (flex > maxFlex) {
     797         269 :           maxFlex = flex;
     798             :         }
     799        1008 :         currentBox->flex = flex;
     800             :       }
     801             : 
     802             :       // we specified all our children are equal size;
     803        1173 :       if (frameState & NS_STATE_EQUAL_SIZE) {
     804             : 
     805           0 :         if (prefWidth > biggestPrefWidth)
     806           0 :           biggestPrefWidth = prefWidth;
     807             : 
     808           0 :         if (minWidth > biggestMinWidth)
     809           0 :           biggestMinWidth = minWidth;
     810             : 
     811           0 :         if (maxWidth < smallestMaxWidth)
     812           0 :           smallestMaxWidth = maxWidth;
     813             :       } else { // not we can set our children right now.
     814        1173 :         currentBox->pref    = prefWidth;
     815        1173 :         currentBox->min     = minWidth;
     816        1173 :         currentBox->max     = maxWidth;
     817             :       }
     818             : 
     819        1173 :       NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,"Bad min, pref, max widths!");
     820             : 
     821             :     }
     822             : 
     823        1173 :     if (!isHorizontal) {
     824         368 :       if (minSize.width > aMinSize)
     825         127 :         aMinSize = minSize.width;
     826             : 
     827         368 :       if (maxSize.width < aMaxSize)
     828           0 :         aMaxSize = maxSize.width;
     829             : 
     830             :     } else {
     831         805 :       if (minSize.height > aMinSize)
     832         251 :         aMinSize = minSize.height;
     833             : 
     834         805 :       if (maxSize.height < aMaxSize)
     835           0 :         aMaxSize = maxSize.height;
     836             :     }
     837             : 
     838        1173 :     currentBox->collapsed = collapsed;
     839        1173 :     aFlexes += currentBox->flex;
     840             : 
     841        1173 :     child = nsBox::GetNextXULBox(child);
     842             : 
     843        1173 :     last = currentBox;
     844        1173 :     currentBox = currentBox->next;
     845             : 
     846             :   }
     847             : 
     848         438 :   if (childCount > 0) {
     849         413 :     nscoord maxAllowedFlex = nscoord_MAX / childCount;
     850             : 
     851         413 :     if (MOZ_UNLIKELY(maxFlex > maxAllowedFlex)) {
     852             :       // clamp all the flexes
     853           0 :       currentBox = aBoxSizes;
     854           0 :       while (currentBox) {
     855           0 :         currentBox->flex = std::min(currentBox->flex, maxAllowedFlex);
     856           0 :         currentBox = currentBox->next;
     857             :       }
     858             :     }
     859             :   }
     860             : #ifdef DEBUG
     861             :   else {
     862          25 :     NS_ASSERTION(maxFlex == 0, "How did that happen?");
     863             :   }
     864             : #endif
     865             : 
     866             :   // we specified all our children are equal size;
     867         438 :   if (frameState & NS_STATE_EQUAL_SIZE) {
     868           0 :     smallestMaxWidth = std::max(smallestMaxWidth, biggestMinWidth);
     869           0 :     biggestPrefWidth = nsBox::BoundsCheck(biggestMinWidth, biggestPrefWidth, smallestMaxWidth);
     870             : 
     871           0 :     currentBox = aBoxSizes;
     872             : 
     873           0 :     while(currentBox)
     874             :     {
     875           0 :       if (!currentBox->collapsed) {
     876           0 :         currentBox->pref = biggestPrefWidth;
     877           0 :         currentBox->min = biggestMinWidth;
     878           0 :         currentBox->max = smallestMaxWidth;
     879             :       } else {
     880           0 :         currentBox->pref = 0;
     881           0 :         currentBox->min = 0;
     882           0 :         currentBox->max = 0;
     883             :       }
     884           0 :       currentBox = currentBox->next;
     885             :     }
     886             :   }
     887             : 
     888         438 : }
     889             : 
     890             : void
     891        1173 : nsSprocketLayout::ComputeChildsNextPosition(nsIFrame* aBox,
     892             :                                       const nscoord& aCurX,
     893             :                                       const nscoord& aCurY,
     894             :                                       nscoord& aNextX,
     895             :                                       nscoord& aNextY,
     896             :                                       const nsRect& aCurrentChildSize)
     897             : {
     898             :   // Get the position along the box axis for the child.
     899             :   // The out-of-axis position is not set.
     900        1173 :   nsFrameState frameState = nsFrameState(0);
     901        1173 :   GetFrameState(aBox, frameState);
     902             : 
     903        1173 :   if (IsXULHorizontal(aBox)) {
     904             :     // horizontal box's children.
     905         805 :     if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
     906         805 :       aNextX = aCurX + aCurrentChildSize.width;
     907             :     else
     908           0 :       aNextX = aCurX - aCurrentChildSize.width;
     909             : 
     910             :   } else {
     911             :     // vertical box's children.
     912         368 :     if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
     913         368 :       aNextY = aCurY + aCurrentChildSize.height;
     914             :     else
     915           0 :       aNextY = aCurY - aCurrentChildSize.height;
     916             :   }
     917        1173 : }
     918             : 
     919             : void
     920         123 : nsSprocketLayout::AlignChildren(nsIFrame* aBox,
     921             :                                 nsBoxLayoutState& aState)
     922             : {
     923         123 :   nsFrameState frameState = nsFrameState(0);
     924         123 :   GetFrameState(aBox, frameState);
     925         123 :   bool isHorizontal = (frameState & NS_STATE_IS_HORIZONTAL) != 0;
     926         246 :   nsRect clientRect;
     927         123 :   aBox->GetXULClientRect(clientRect);
     928             : 
     929         123 :   NS_PRECONDITION(!(frameState & NS_STATE_AUTO_STRETCH),
     930             :                   "Only AlignChildren() with non-stretch alignment");
     931             : 
     932             :   // These are only calculated if needed
     933             :   nsIFrame::Halignment halign;
     934             :   nsIFrame::Valignment valign;
     935         123 :   nscoord maxAscent = 0;
     936             :   bool isLTR;
     937             : 
     938         123 :   if (isHorizontal) {
     939         118 :     valign = aBox->GetXULVAlign();
     940         118 :     if (valign == nsBoxFrame::vAlign_BaseLine) {
     941           0 :       maxAscent = aBox->GetXULBoxAscent(aState);
     942             :     }
     943             :   } else {
     944           5 :     isLTR = GetFrameDirection(aBox) == NS_STYLE_DIRECTION_LTR;
     945           5 :     halign = aBox->GetXULHAlign();
     946             :   }
     947             : 
     948         123 :   nsIFrame* child = nsBox::GetChildXULBox(aBox);
     949         567 :   while (child) {
     950             : 
     951         222 :     nsMargin margin;
     952         222 :     child->GetXULMargin(margin);
     953         444 :     nsRect childRect = child->GetRect();
     954             : 
     955         222 :     if (isHorizontal) {
     956         220 :       const nscoord startAlign = clientRect.y + margin.top;
     957             :       const nscoord endAlign =
     958         220 :         clientRect.YMost() - margin.bottom - childRect.height;
     959             : 
     960         220 :       nscoord y = 0;
     961         220 :       switch (valign) {
     962             :         case nsBoxFrame::vAlign_Top:
     963           0 :           y = startAlign;
     964           0 :           break;
     965             :         case nsBoxFrame::vAlign_Middle:
     966             :           // Should this center the border box?
     967             :           // This centers the margin box, the historical behavior.
     968         215 :           y = (startAlign + endAlign) / 2;
     969         215 :           break;
     970             :         case nsBoxFrame::vAlign_Bottom:
     971           5 :           y = endAlign;
     972           5 :           break;
     973             :         case nsBoxFrame::vAlign_BaseLine:
     974             :           // Alignments don't force the box to grow (only sizes do),
     975             :           // so keep the children within the box.
     976           0 :           y = maxAscent - child->GetXULBoxAscent(aState);
     977           0 :           y = std::max(startAlign, y);
     978           0 :           y = std::min(y, endAlign);
     979           0 :           break;
     980             :       }
     981             : 
     982         220 :       childRect.y = y;
     983             : 
     984             :     } else { // vertical box
     985           2 :       const nscoord leftAlign = clientRect.x + margin.left;
     986             :       const nscoord rightAlign =
     987           2 :         clientRect.XMost() - margin.right - childRect.width;
     988             : 
     989           2 :       nscoord x = 0;
     990           2 :       switch (halign) {
     991             :         case nsBoxFrame::hAlign_Left: // start
     992           0 :           x = isLTR ? leftAlign : rightAlign;
     993           0 :           break;
     994             :         case nsBoxFrame::hAlign_Center:
     995           2 :           x = (leftAlign + rightAlign) / 2;
     996           2 :           break;
     997             :         case nsBoxFrame::hAlign_Right: // end
     998           0 :           x = isLTR ? rightAlign : leftAlign;
     999           0 :           break;
    1000             :       }
    1001             : 
    1002           2 :       childRect.x = x;
    1003             :     }
    1004             : 
    1005         222 :     if (childRect.TopLeft() != child->GetPosition()) {
    1006          87 :       child->SetXULBounds(aState, childRect);
    1007             :     }
    1008             : 
    1009         222 :     child = nsBox::GetNextXULBox(child);
    1010             :   }
    1011         123 : }
    1012             : 
    1013             : void
    1014           0 : nsSprocketLayout::ChildResized(nsIFrame* aBox,
    1015             :                          nsBoxLayoutState& aState,
    1016             :                          nsIFrame* aChild,
    1017             :                          nsBoxSize* aChildBoxSize,
    1018             :                          nsComputedBoxSize* aChildComputedSize,
    1019             :                          nsBoxSize* aBoxSizes,
    1020             :                          nsComputedBoxSize* aComputedBoxSizes,
    1021             :                          const nsRect& aChildLayoutRect,
    1022             :                          nsRect& aChildActualRect,
    1023             :                          nsRect& aContainingRect,
    1024             :                          int32_t aFlexes,
    1025             :                          bool& aFinished)
    1026             : 
    1027             : {
    1028           0 :       nsRect childCurrentRect(aChildLayoutRect);
    1029             : 
    1030           0 :       bool isHorizontal = IsXULHorizontal(aBox);
    1031           0 :       nscoord childLayoutWidth  = GET_WIDTH(aChildLayoutRect,isHorizontal);
    1032           0 :       nscoord& childActualWidth  = GET_WIDTH(aChildActualRect,isHorizontal);
    1033           0 :       nscoord& containingWidth   = GET_WIDTH(aContainingRect,isHorizontal);
    1034             : 
    1035             :       //nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal);
    1036           0 :       nscoord& childActualHeight = GET_HEIGHT(aChildActualRect,isHorizontal);
    1037           0 :       nscoord& containingHeight  = GET_HEIGHT(aContainingRect,isHorizontal);
    1038             : 
    1039           0 :       bool recompute = false;
    1040             : 
    1041             :       // if we are a horizontal box see if the child will fit inside us.
    1042           0 :       if ( childActualHeight > containingHeight) {
    1043             :             // if we are a horizontal box and the child is bigger than our height
    1044             : 
    1045             :             // ok if the height changed then we need to reflow everyone but us at the new height
    1046             :             // so we will set the changed index to be us. And signal that we need a new pass.
    1047             : 
    1048           0 :             nsSize min = aChild->GetXULMinSize(aState);
    1049           0 :             nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetXULMaxSize(aState));
    1050           0 :             AddMargin(aChild, max);
    1051             : 
    1052           0 :             if (isHorizontal)
    1053           0 :               childActualHeight = max.height < childActualHeight ? max.height : childActualHeight;
    1054             :             else
    1055           0 :               childActualHeight = max.width < childActualHeight ? max.width : childActualHeight;
    1056             : 
    1057             :             // only set if it changes
    1058           0 :             if (childActualHeight > containingHeight) {
    1059           0 :                  containingHeight = childActualHeight;
    1060             : 
    1061             :               // remember we do not need to clear the resized list because changing the height of a horizontal box
    1062             :               // will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me
    1063             :               // on this one.
    1064           0 :               aFinished = false;
    1065             : 
    1066             :               // only recompute if there are flexes.
    1067           0 :               if (aFlexes > 0) {
    1068             :                 // relayout everything
    1069           0 :                 recompute = true;
    1070           0 :                 InvalidateComputedSizes(aComputedBoxSizes);
    1071           0 :                 nsComputedBoxSize* node = aComputedBoxSizes;
    1072             : 
    1073           0 :                 while(node) {
    1074           0 :                   node->resized = false;
    1075           0 :                   node = node->next;
    1076             :                 }
    1077             : 
    1078             :               }
    1079             :             }
    1080             :       }
    1081             : 
    1082           0 :       if (childActualWidth > childLayoutWidth) {
    1083           0 :             nsSize min = aChild->GetXULMinSize(aState);
    1084           0 :             nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetXULMaxSize(aState));
    1085             : 
    1086           0 :             AddMargin(aChild, max);
    1087             : 
    1088             :             // our width now becomes the new size
    1089             : 
    1090           0 :             if (isHorizontal)
    1091           0 :               childActualWidth = max.width < childActualWidth ? max.width : childActualWidth;
    1092             :             else
    1093           0 :               childActualWidth = max.height < childActualWidth ? max.height : childActualWidth;
    1094             : 
    1095           0 :             if (childActualWidth > childLayoutWidth) {
    1096           0 :                aChildComputedSize->size = childActualWidth;
    1097           0 :                aChildBoxSize->min = childActualWidth;
    1098           0 :                if (aChildBoxSize->pref < childActualWidth)
    1099           0 :                   aChildBoxSize->pref = childActualWidth;
    1100           0 :                if (aChildBoxSize->max < childActualWidth)
    1101           0 :                   aChildBoxSize->max = childActualWidth;
    1102             : 
    1103             :               // if we have flexible elements with us then reflex things. Otherwise we can skip doing it.
    1104           0 :               if (aFlexes > 0) {
    1105           0 :                 InvalidateComputedSizes(aComputedBoxSizes);
    1106             : 
    1107           0 :                 nsComputedBoxSize* node = aComputedBoxSizes;
    1108           0 :                 aChildComputedSize->resized = true;
    1109             : 
    1110           0 :                 while(node) {
    1111           0 :                   if (node->resized)
    1112           0 :                       node->valid = true;
    1113             : 
    1114           0 :                   node = node->next;
    1115             :                 }
    1116             : 
    1117           0 :                 recompute = true;
    1118           0 :                 aFinished = false;
    1119             :               } else {
    1120           0 :                 containingWidth += aChildComputedSize->size - childLayoutWidth;
    1121             :               }
    1122             :             }
    1123             :       }
    1124             : 
    1125           0 :       if (recompute)
    1126           0 :             ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes, aComputedBoxSizes);
    1127             : 
    1128           0 :       if (!childCurrentRect.IsEqualInterior(aChildActualRect)) {
    1129             :         // the childRect includes the margin
    1130             :         // make sure we remove it before setting
    1131             :         // the bounds.
    1132           0 :         nsMargin margin(0,0,0,0);
    1133           0 :         aChild->GetXULMargin(margin);
    1134           0 :         nsRect rect(aChildActualRect);
    1135           0 :         if (rect.width >= margin.left + margin.right && rect.height >= margin.top + margin.bottom)
    1136           0 :           rect.Deflate(margin);
    1137             : 
    1138           0 :         aChild->SetXULBounds(aState, rect);
    1139           0 :         aChild->XULLayout(aState);
    1140             :       }
    1141             : 
    1142           0 : }
    1143             : 
    1144             : void
    1145           0 : nsSprocketLayout::InvalidateComputedSizes(nsComputedBoxSize* aComputedBoxSizes)
    1146             : {
    1147           0 :   while(aComputedBoxSizes) {
    1148           0 :       aComputedBoxSizes->valid = false;
    1149           0 :       aComputedBoxSizes = aComputedBoxSizes->next;
    1150             :   }
    1151           0 : }
    1152             : 
    1153             : void
    1154         438 : nsSprocketLayout::ComputeChildSizes(nsIFrame* aBox,
    1155             :                            nsBoxLayoutState& aState,
    1156             :                            nscoord& aGivenSize,
    1157             :                            nsBoxSize* aBoxSizes,
    1158             :                            nsComputedBoxSize*& aComputedBoxSizes)
    1159             : {
    1160             : 
    1161             :   //nscoord onePixel = aState.PresContext()->IntScaledPixelsToTwips(1);
    1162             : 
    1163         438 :   int32_t sizeRemaining            = aGivenSize;
    1164         438 :   int32_t spacerConstantsRemaining = 0;
    1165             : 
    1166             :    // ----- calculate the spacers constants and the size remaining -----
    1167             : 
    1168         438 :   if (!aComputedBoxSizes)
    1169         438 :       aComputedBoxSizes = new (aState) nsComputedBoxSize();
    1170             : 
    1171         438 :   nsBoxSize*         boxSizes = aBoxSizes;
    1172         438 :   nsComputedBoxSize* computedBoxSizes = aComputedBoxSizes;
    1173         438 :   int32_t count = 0;
    1174         438 :   int32_t validCount = 0;
    1175             : 
    1176        2784 :   while (boxSizes)
    1177             :   {
    1178             : 
    1179        1173 :     NS_ASSERTION((boxSizes->min <= boxSizes->pref && boxSizes->pref <= boxSizes->max),"bad pref, min, max size");
    1180             : 
    1181             : 
    1182             :      // ignore collapsed children
    1183             :   //  if (boxSizes->collapsed)
    1184             :   //  {
    1185             :     //  computedBoxSizes->valid = true;
    1186             :     //  computedBoxSizes->size = boxSizes->pref;
    1187             :      // validCount++;
    1188             :   //      boxSizes->flex = 0;
    1189             :    // }// else {
    1190             : 
    1191        1173 :       if (computedBoxSizes->valid) {
    1192           0 :         sizeRemaining -= computedBoxSizes->size;
    1193           0 :         validCount++;
    1194             :       } else {
    1195        1173 :           if (boxSizes->flex == 0)
    1196             :           {
    1197         892 :             computedBoxSizes->valid = true;
    1198         892 :             computedBoxSizes->size = boxSizes->pref;
    1199         892 :             validCount++;
    1200             :           }
    1201             : 
    1202        1173 :           spacerConstantsRemaining += boxSizes->flex;
    1203        1173 :           sizeRemaining -= boxSizes->pref;
    1204             :       }
    1205             : 
    1206        1173 :       sizeRemaining -= (boxSizes->left + boxSizes->right);
    1207             : 
    1208             :     //}
    1209             : 
    1210        1173 :     boxSizes = boxSizes->next;
    1211             : 
    1212        1173 :     if (boxSizes && !computedBoxSizes->next)
    1213         760 :       computedBoxSizes->next = new (aState) nsComputedBoxSize();
    1214             : 
    1215        1173 :     computedBoxSizes = computedBoxSizes->next;
    1216        1173 :     count++;
    1217             :   }
    1218             : 
    1219             :   // everything accounted for?
    1220         438 :   if (validCount < count)
    1221             :   {
    1222             :     // ----- Ok we are give a size to fit into so stretch or squeeze to fit
    1223             :     // ----- Make sure we look at our min and max size
    1224         269 :     bool limit = true;
    1225         576 :     for (int pass=1; true == limit; pass++)
    1226             :     {
    1227         307 :       limit = false;
    1228         307 :       boxSizes = aBoxSizes;
    1229         307 :       computedBoxSizes = aComputedBoxSizes;
    1230             : 
    1231        2169 :       while (boxSizes) {
    1232             : 
    1233             :         // ignore collapsed spacers
    1234             : 
    1235             :    //    if (!boxSizes->collapsed) {
    1236             : 
    1237         931 :           nscoord pref = 0;
    1238         931 :           nscoord max  = NS_INTRINSICSIZE;
    1239         931 :           nscoord min  = 0;
    1240         931 :           nscoord flex = 0;
    1241             : 
    1242         931 :           pref = boxSizes->pref;
    1243         931 :           min  = boxSizes->min;
    1244         931 :           max  = boxSizes->max;
    1245         931 :           flex = boxSizes->flex;
    1246             : 
    1247             :           // ----- look at our min and max limits make sure we aren't too small or too big -----
    1248         931 :           if (!computedBoxSizes->valid) {
    1249         281 :             int32_t newSize = pref + int32_t(int64_t(sizeRemaining) * flex / spacerConstantsRemaining);
    1250             : 
    1251         281 :             if (newSize<=min) {
    1252          31 :               computedBoxSizes->size = min;
    1253          31 :               computedBoxSizes->valid = true;
    1254          31 :               spacerConstantsRemaining -= flex;
    1255          31 :               sizeRemaining += pref;
    1256          31 :               sizeRemaining -= min;
    1257          31 :               limit = true;
    1258         250 :             } else if (newSize>=max) {
    1259          10 :               computedBoxSizes->size = max;
    1260          10 :               computedBoxSizes->valid = true;
    1261          10 :               spacerConstantsRemaining -= flex;
    1262          10 :               sizeRemaining += pref;
    1263          10 :               sizeRemaining -= max;
    1264          10 :               limit = true;
    1265             :             }
    1266             :           }
    1267             :        // }
    1268         931 :         boxSizes         = boxSizes->next;
    1269         931 :         computedBoxSizes = computedBoxSizes->next;
    1270             :       }
    1271             :     }
    1272             :   }
    1273             : 
    1274             :   // ---- once we have removed and min and max issues just stretch us out in the remaining space
    1275             :   // ---- or shrink us. Depends on the size remaining and the spacer constants
    1276         438 :   aGivenSize = 0;
    1277         438 :   boxSizes = aBoxSizes;
    1278         438 :   computedBoxSizes = aComputedBoxSizes;
    1279             : 
    1280        2784 :   while (boxSizes) {
    1281             : 
    1282             :     // ignore collapsed spacers
    1283             :   //  if (!(boxSizes && boxSizes->collapsed)) {
    1284             : 
    1285        1173 :       nscoord pref = 0;
    1286        1173 :       nscoord flex = 0;
    1287        1173 :       pref = boxSizes->pref;
    1288        1173 :       flex = boxSizes->flex;
    1289             : 
    1290        1173 :       if (!computedBoxSizes->valid) {
    1291         240 :         computedBoxSizes->size = pref + int32_t(int64_t(sizeRemaining) * flex / spacerConstantsRemaining);
    1292         240 :         computedBoxSizes->valid = true;
    1293             :       }
    1294             : 
    1295        1173 :       aGivenSize += (boxSizes->left + boxSizes->right);
    1296        1173 :       aGivenSize += computedBoxSizes->size;
    1297             : 
    1298             :    // }
    1299             : 
    1300        1173 :     boxSizes         = boxSizes->next;
    1301        1173 :     computedBoxSizes = computedBoxSizes->next;
    1302             :   }
    1303         438 : }
    1304             : 
    1305             : 
    1306             : nsSize
    1307         324 : nsSprocketLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
    1308             : {
    1309         324 :    nsSize vpref (0, 0);
    1310         324 :    bool isHorizontal = IsXULHorizontal(aBox);
    1311             : 
    1312         324 :    nscoord biggestPref = 0;
    1313             : 
    1314             :    // run through all the children and get their min, max, and preferred sizes
    1315             :    // return us the size of the box
    1316             : 
    1317         324 :    nsIFrame* child = nsBox::GetChildXULBox(aBox);
    1318         324 :    nsFrameState frameState = nsFrameState(0);
    1319         324 :    GetFrameState(aBox, frameState);
    1320         324 :    bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
    1321         324 :    int32_t count = 0;
    1322             : 
    1323        1998 :    while (child)
    1324             :    {
    1325             :       // ignore collapsed children
    1326         837 :       if (!child->IsXULCollapsed())
    1327             :       {
    1328         707 :         nsSize pref = child->GetXULPrefSize(aState);
    1329         707 :         AddMargin(child, pref);
    1330             : 
    1331         707 :         if (isEqual) {
    1332           0 :           if (isHorizontal)
    1333             :           {
    1334           0 :             if (pref.width > biggestPref)
    1335           0 :               biggestPref = pref.width;
    1336             :           } else {
    1337           0 :             if (pref.height > biggestPref)
    1338           0 :               biggestPref = pref.height;
    1339             :           }
    1340             :         }
    1341             : 
    1342         707 :         AddLargestSize(vpref, pref, isHorizontal);
    1343         707 :         count++;
    1344             :       }
    1345             : 
    1346         837 :       child = nsBox::GetNextXULBox(child);
    1347             :    }
    1348             : 
    1349         324 :    if (isEqual) {
    1350           0 :       if (isHorizontal)
    1351           0 :          vpref.width = biggestPref*count;
    1352             :       else
    1353           0 :          vpref.height = biggestPref*count;
    1354             :    }
    1355             : 
    1356             :    // now add our border and padding
    1357         324 :    AddBorderAndPadding(aBox, vpref);
    1358             : 
    1359         324 :   return vpref;
    1360             : }
    1361             : 
    1362             : nsSize
    1363         300 : nsSprocketLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
    1364             : {
    1365         300 :    nsSize minSize (0, 0);
    1366         300 :    bool isHorizontal = IsXULHorizontal(aBox);
    1367             : 
    1368         300 :    nscoord biggestMin = 0;
    1369             : 
    1370             : 
    1371             :    // run through all the children and get their min, max, and preferred sizes
    1372             :    // return us the size of the box
    1373             : 
    1374         300 :    nsIFrame* child = nsBox::GetChildXULBox(aBox);
    1375         300 :    nsFrameState frameState = nsFrameState(0);
    1376         300 :    GetFrameState(aBox, frameState);
    1377         300 :    bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
    1378         300 :    int32_t count = 0;
    1379             : 
    1380        2014 :    while (child)
    1381             :    {
    1382             :        // ignore collapsed children
    1383         857 :       if (!child->IsXULCollapsed())
    1384             :       {
    1385         714 :         nsSize min = child->GetXULMinSize(aState);
    1386         714 :         nsSize pref(0,0);
    1387             : 
    1388             :         // if the child is not flexible then
    1389             :         // its min size is its pref size.
    1390         714 :         if (child->GetXULFlex() == 0) {
    1391         533 :             pref = child->GetXULPrefSize(aState);
    1392         533 :             if (isHorizontal)
    1393         307 :                min.width = pref.width;
    1394             :             else
    1395         226 :                min.height = pref.height;
    1396             :         }
    1397             : 
    1398         714 :         if (isEqual) {
    1399           0 :           if (isHorizontal)
    1400             :           {
    1401           0 :             if (min.width > biggestMin)
    1402           0 :               biggestMin = min.width;
    1403             :           } else {
    1404           0 :             if (min.height > biggestMin)
    1405           0 :               biggestMin = min.height;
    1406             :           }
    1407             :         }
    1408             : 
    1409         714 :         AddMargin(child, min);
    1410         714 :         AddLargestSize(minSize, min, isHorizontal);
    1411         714 :         count++;
    1412             :       }
    1413             : 
    1414         857 :       child = nsBox::GetNextXULBox(child);
    1415             :    }
    1416             : 
    1417             : 
    1418         300 :    if (isEqual) {
    1419           0 :       if (isHorizontal)
    1420           0 :          minSize.width = biggestMin*count;
    1421             :       else
    1422           0 :          minSize.height = biggestMin*count;
    1423             :    }
    1424             : 
    1425             :   // now add our border and padding
    1426         300 :   AddBorderAndPadding(aBox, minSize);
    1427             : 
    1428         300 :   return minSize;
    1429             : }
    1430             : 
    1431             : nsSize
    1432         320 : nsSprocketLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
    1433             : {
    1434             : 
    1435         320 :   bool isHorizontal = IsXULHorizontal(aBox);
    1436             : 
    1437         320 :    nscoord smallestMax = NS_INTRINSICSIZE;
    1438         320 :    nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
    1439             : 
    1440             :    // run through all the children and get their min, max, and preferred sizes
    1441             :    // return us the size of the box
    1442             : 
    1443         320 :    nsIFrame* child = nsBox::GetChildXULBox(aBox);
    1444         320 :    nsFrameState frameState = nsFrameState(0);
    1445         320 :    GetFrameState(aBox, frameState);
    1446         320 :    bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
    1447         320 :    int32_t count = 0;
    1448             : 
    1449        2142 :    while (child)
    1450             :    {
    1451             :       // ignore collapsed children
    1452         911 :       if (!child->IsXULCollapsed())
    1453             :       {
    1454             :         // if completely redefined don't even ask our child for its size.
    1455         762 :         nsSize min = child->GetXULMinSize(aState);
    1456         762 :         nsSize max = nsBox::BoundsCheckMinMax(min, child->GetXULMaxSize(aState));
    1457             : 
    1458         762 :         AddMargin(child, max);
    1459         762 :         AddSmallestSize(maxSize, max, isHorizontal);
    1460             : 
    1461         762 :         if (isEqual) {
    1462           0 :           if (isHorizontal)
    1463             :           {
    1464           0 :             if (max.width < smallestMax)
    1465           0 :               smallestMax = max.width;
    1466             :           } else {
    1467           0 :             if (max.height < smallestMax)
    1468           0 :               smallestMax = max.height;
    1469             :           }
    1470             :         }
    1471         762 :         count++;
    1472             :       }
    1473             : 
    1474         911 :       child = nsBox::GetNextXULBox(child);
    1475             :    }
    1476             : 
    1477         320 :    if (isEqual) {
    1478           0 :      if (isHorizontal) {
    1479           0 :          if (smallestMax != NS_INTRINSICSIZE)
    1480           0 :             maxSize.width = smallestMax*count;
    1481             :          else
    1482           0 :             maxSize.width = NS_INTRINSICSIZE;
    1483             :      } else {
    1484           0 :          if (smallestMax != NS_INTRINSICSIZE)
    1485           0 :             maxSize.height = smallestMax*count;
    1486             :          else
    1487           0 :             maxSize.height = NS_INTRINSICSIZE;
    1488             :      }
    1489             :    }
    1490             : 
    1491             :   // now add our border and padding
    1492         320 :   AddBorderAndPadding(aBox, maxSize);
    1493             : 
    1494         320 :   return maxSize;
    1495             : }
    1496             : 
    1497             : 
    1498             : nscoord
    1499         600 : nsSprocketLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState)
    1500             : {
    1501         600 :    nscoord vAscent = 0;
    1502             : 
    1503         600 :    bool isHorizontal = IsXULHorizontal(aBox);
    1504             : 
    1505             :    // run through all the children and get their min, max, and preferred sizes
    1506             :    // return us the size of the box
    1507             : 
    1508         600 :    nsIFrame* child = nsBox::GetChildXULBox(aBox);
    1509             : 
    1510        3516 :    while (child)
    1511             :    {
    1512             :       // ignore collapsed children
    1513             :       //if (!child->IsXULCollapsed())
    1514             :       //{
    1515             :         // if completely redefined don't even ask our child for its size.
    1516        1458 :         nscoord ascent = child->GetXULBoxAscent(aState);
    1517             : 
    1518        1458 :         nsMargin margin;
    1519        1458 :         child->GetXULMargin(margin);
    1520        1458 :         ascent += margin.top;
    1521             : 
    1522        1458 :         if (isHorizontal)
    1523             :         {
    1524        1172 :           if (ascent > vAscent)
    1525         462 :             vAscent = ascent;
    1526             :         } else {
    1527         286 :           if (vAscent == 0)
    1528         108 :             vAscent = ascent;
    1529             :         }
    1530             :       //}
    1531             : 
    1532        1458 :       child = nsBox::GetNextXULBox(child);
    1533             :    }
    1534             : 
    1535         600 :    nsMargin borderPadding;
    1536         600 :    aBox->GetXULBorderAndPadding(borderPadding);
    1537             : 
    1538         600 :    return vAscent + borderPadding.top;
    1539             : }
    1540             : 
    1541             : void
    1542        1421 : nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal)
    1543             : {
    1544        1421 :   if (aIsHorizontal)
    1545             :   {
    1546         941 :     if (aSize1.height < aSize2.height)
    1547         397 :        aSize1.height = aSize2.height;
    1548             :   } else {
    1549         480 :     if (aSize1.width < aSize2.width)
    1550         188 :        aSize1.width = aSize2.width;
    1551             :   }
    1552        1421 : }
    1553             : 
    1554             : void
    1555         762 : nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal)
    1556             : {
    1557         762 :   if (aIsHorizontal)
    1558             :   {
    1559         482 :     if (aSize1.height > aSize2.height)
    1560           0 :        aSize1.height = aSize2.height;
    1561             :   } else {
    1562         280 :     if (aSize1.width > aSize2.width)
    1563           0 :        aSize1.width = aSize2.width;
    1564             : 
    1565             :   }
    1566         762 : }
    1567             : 
    1568             : void
    1569        1421 : nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal)
    1570             : {
    1571        1421 :   if (aIsHorizontal)
    1572         941 :     AddCoord(aSize.width, aSizeToAdd.width);
    1573             :   else
    1574         480 :     AddCoord(aSize.height, aSizeToAdd.height);
    1575             : 
    1576        1421 :   SetLargestSize(aSize, aSizeToAdd, aIsHorizontal);
    1577        1421 : }
    1578             : 
    1579             : void
    1580        2183 : nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd)
    1581             : {
    1582        2183 :   if (aCoord != NS_INTRINSICSIZE)
    1583             :   {
    1584        1421 :     if (aCoordToAdd == NS_INTRINSICSIZE)
    1585           0 :       aCoord = aCoordToAdd;
    1586             :     else
    1587        1421 :       aCoord += aCoordToAdd;
    1588             :   }
    1589        2183 : }
    1590             : void
    1591         762 : nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal)
    1592             : {
    1593         762 :   if (aIsHorizontal)
    1594         482 :     AddCoord(aSize.width, aSizeToAdd.width);
    1595             :   else
    1596         280 :     AddCoord(aSize.height, aSizeToAdd.height);
    1597             : 
    1598         762 :   SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal);
    1599         762 : }
    1600             : 
    1601             : bool
    1602           0 : nsSprocketLayout::GetDefaultFlex(int32_t& aFlex)
    1603             : {
    1604           0 :     aFlex = 0;
    1605           0 :     return true;
    1606             : }
    1607             : 
    1608        1198 : nsComputedBoxSize::nsComputedBoxSize()
    1609             : {
    1610        1198 :   resized = false;
    1611        1198 :   valid = false;
    1612        1198 :   size = 0;
    1613        1198 :   next = nullptr;
    1614        1198 : }
    1615             : 
    1616        1173 : nsBoxSize::nsBoxSize()
    1617             : {
    1618        1173 :   pref = 0;
    1619        1173 :   min = 0;
    1620        1173 :   max = NS_INTRINSICSIZE;
    1621        1173 :   collapsed = false;
    1622        1173 :   left = 0;
    1623        1173 :   right = 0;
    1624        1173 :   flex = 0;
    1625        1173 :   next = nullptr;
    1626        1173 :   bogus = false;
    1627        1173 : }
    1628             : 
    1629             : 
    1630             : void*
    1631        1173 : nsBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
    1632             : {
    1633        1173 :   return mozilla::AutoStackArena::Allocate(sz);
    1634             : }
    1635             : 
    1636             : 
    1637             : void
    1638        1173 : nsBoxSize::operator delete(void* aPtr, size_t sz)
    1639             : {
    1640        1173 : }
    1641             : 
    1642             : 
    1643             : void*
    1644        1198 : nsComputedBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
    1645             : {
    1646        1198 :    return mozilla::AutoStackArena::Allocate(sz);
    1647             : }
    1648             : 
    1649             : void
    1650        1198 : nsComputedBoxSize::operator delete(void* aPtr, size_t sz)
    1651             : {
    1652        1198 : }

Generated by: LCOV version 1.13