layout/xul/nsSprocketLayout.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing 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/. */
     6 //
     7 // Eric Vaughan
     8 // Netscape Communications
     9 //
    10 // See documentation in associated header file
    11 //
    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>
    25 nsBoxLayout* nsSprocketLayout::gInstance = nullptr;
    27 //#define DEBUG_GROW
    29 #define DEBUG_SPRING_SIZE 8
    30 #define DEBUG_BORDER_SIZE 2
    31 #define COIL_SIZE 8
    34 nsresult
    35 NS_NewSprocketLayout( nsIPresShell* aPresShell, nsCOMPtr<nsBoxLayout>& aNewLayout)
    36 {
    37   if (!nsSprocketLayout::gInstance) {
    38     nsSprocketLayout::gInstance = new nsSprocketLayout();
    39     NS_IF_ADDREF(nsSprocketLayout::gInstance);
    40   }
    41   // we have not instance variables so just return our static one.
    42   aNewLayout = nsSprocketLayout::gInstance;
    43   return NS_OK;
    44 } 
    46 /*static*/ void
    47 nsSprocketLayout::Shutdown()
    48 {
    49   NS_IF_RELEASE(gInstance);
    50 }
    52 nsSprocketLayout::nsSprocketLayout()
    53 {
    54 }
    56 bool 
    57 nsSprocketLayout::IsHorizontal(nsIFrame* aBox)
    58 {
    59    return (aBox->GetStateBits() & NS_STATE_IS_HORIZONTAL) != 0;
    60 }
    62 void
    63 nsSprocketLayout::GetFrameState(nsIFrame* aBox, nsFrameState& aState)
    64 {
    65    aState = aBox->GetStateBits();
    66 }
    68 static uint8_t
    69 GetFrameDirection(nsIFrame* aBox)
    70 {
    71    return aBox->StyleVisibility()->mDirection;
    72 }
    74 static void
    75 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   uint8_t frameDirection = GetFrameDirection(aBox);
    84   if (aFrameState & NS_STATE_IS_HORIZONTAL) {
    85     if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
    86       // The normal direction. |x| increases as we move through our children.
    87       aX = aClientRect.x;
    88     }
    89     else {
    90       // The reverse direction. |x| decreases as we move through our children.
    91       aX = aClientRect.x + aOriginalRect.width;
    92     }
    93     // |y| is always in the normal direction in horizontal boxes
    94     aY = aClientRect.y;    
    95   }
    96   else {
    97     // take direction property into account for |x| in vertical boxes
    98     if (frameDirection == NS_STYLE_DIRECTION_LTR) {
    99       // The normal direction. |x| increases as we move through our children.
   100       aX = aClientRect.x;
   101     }
   102     else {
   103       // The reverse direction. |x| decreases as we move through our children.
   104       aX = aClientRect.x + aOriginalRect.width;
   105     }
   106     if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
   107       // The normal direction. |y| increases as we move through our children.
   108       aY = aClientRect.y;
   109     }
   110     else {
   111       // The reverse direction. |y| decreases as we move through our children.
   112       aY = aClientRect.y + aOriginalRect.height;
   113     }
   114   }
   116   // Get our pack/alignment information.
   117   nsIFrame::Halignment halign = aBox->GetHAlign();
   118   nsIFrame::Valignment valign = aBox->GetVAlign();
   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   if (aFrameState & NS_STATE_IS_HORIZONTAL) {
   129     switch(halign) {
   130       case nsBoxFrame::hAlign_Left:
   131         break; // Nothing to do.  The default initialized us properly.
   133       case nsBoxFrame::hAlign_Center:
   134         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
   135           aX += (aOriginalRect.width - aClientRect.width)/2;
   136         else 
   137           aX -= (aOriginalRect.width - aClientRect.width)/2;
   138         break;
   140       case nsBoxFrame::hAlign_Right:
   141         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
   142           aX += (aOriginalRect.width - aClientRect.width);
   143         else
   144           aX -= (aOriginalRect.width - aClientRect.width);
   145         break; // Nothing to do for the reverse dir.  The default initialized us properly.
   146     }
   147   } else {
   148     switch(valign) {
   149       case nsBoxFrame::vAlign_Top:
   150       case nsBoxFrame::vAlign_BaseLine: // This value is technically impossible to specify for pack.
   151         break;  // Don't do anything.  We were initialized correctly.
   153       case nsBoxFrame::vAlign_Middle:
   154         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
   155           aY += (aOriginalRect.height - aClientRect.height)/2;
   156         else
   157           aY -= (aOriginalRect.height - aClientRect.height)/2;
   158         break;
   160       case nsBoxFrame::vAlign_Bottom:
   161         if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
   162           aY += (aOriginalRect.height - aClientRect.height);
   163         else
   164           aY -= (aOriginalRect.height - aClientRect.height);
   165         break;
   166     }
   167   }
   168 }
   170 NS_IMETHODIMP
   171 nsSprocketLayout::Layout(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   if (aBox->IsCollapsed()) {
   176     nsIFrame* child = aBox->GetChildBox();
   177     while(child) 
   178     {
   179       nsBoxFrame::LayoutChildAt(aState, child, nsRect(0,0,0,0));  
   180       child = child->GetNextBox();
   181     }
   182     return NS_OK;
   183   }
   185   nsBoxLayoutState::AutoReflowDepth depth(aState);
   186   mozilla::AutoStackArena arena;
   188   // ----- figure out our size ----------
   189   const nsSize originalSize = aBox->GetSize();
   191   // -- make sure we remove our border and padding  ----
   192   nsRect clientRect;
   193   aBox->GetClientRect(clientRect);
   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   nsRect originalClientRect(clientRect);
   204   // The frame state contains cached knowledge about our box, such as our orientation
   205   // and direction.
   206   nsFrameState frameState = nsFrameState(0);
   207   GetFrameState(aBox, frameState);
   209   // Build a list of our children's desired sizes and computed sizes
   210   nsBoxSize*         boxSizes = nullptr;
   211   nsComputedBoxSize* computedBoxSizes = nullptr;
   213   nscoord min = 0;
   214   nscoord max = 0;
   215   int32_t flexes = 0;
   216   PopulateBoxSizes(aBox, aState, boxSizes, min, max, flexes);
   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   nscoord size = clientRect.width;
   222   if (!IsHorizontal(aBox))
   223     size = clientRect.height;
   224   ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes);
   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   if (IsHorizontal(aBox)) {
   236     clientRect.width = size;
   237     if (clientRect.height < min)
   238       clientRect.height = min;
   240     if (frameState & NS_STATE_AUTO_STRETCH) {
   241       if (clientRect.height > max)
   242         clientRect.height = max;
   243     }
   244   } else {
   245     clientRect.height = size;
   246     if (clientRect.width < min)
   247       clientRect.width = min;
   249     if (frameState & NS_STATE_AUTO_STRETCH) {
   250       if (clientRect.width > max)
   251         clientRect.width = max;
   252     }
   253   }
   255   // With the sizes computed, now it's time to lay out our children.
   256   bool finished;
   257   nscoord passes = 0;
   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   nscoord x = 0;
   264   nscoord y = 0;
   265   nscoord origX = 0;
   266   nscoord origY = 0;
   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   bool childResized = false;
   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   passes = 0;
   275   do 
   276   { 
   277 #ifdef DEBUG_REFLOW
   278     if (passes > 0) {
   279       AddIndents();
   280       printf("ChildResized doing pass: %d\n", passes);
   281     }
   282 #endif 
   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     finished = true;
   288     // Handle box packing.
   289     HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
   291     // Now that packing is taken care of we set up a few additional
   292     // tracking variables.
   293     origX = x;
   294     origY = y;
   296     nscoord nextX = x;
   297     nscoord nextY = y;
   299     // Now we iterate over our box children and our box size lists in 
   300     // parallel.  For each child, we look at its sizes and figure out
   301     // where to place it.
   302     nsComputedBoxSize* childComputedBoxSize = computedBoxSizes;
   303     nsBoxSize* childBoxSize                 = boxSizes;
   305     nsIFrame* child = aBox->GetChildBox();
   307     int32_t count = 0;
   308     while (child || (childBoxSize && childBoxSize->bogus))
   309     { 
   310       // If for some reason, our lists are not the same length, we guard
   311       // by bailing out of the loop.
   312       if (childBoxSize == nullptr) {
   313         NS_NOTREACHED("Lists not the same length.");
   314         break;
   315       }
   317       nscoord width = clientRect.width;
   318       nscoord height = clientRect.height;
   320       if (!childBoxSize->bogus) {
   321         // We have a valid box size entry.  This entry already contains information about our
   322         // sizes along the axis of the box (e.g., widths in a horizontal box).  If our default
   323         // ALIGN is not stretch, however, then we also need to know the child's size along the
   324         // opposite axis.
   325         if (!(frameState & NS_STATE_AUTO_STRETCH)) {
   326            nsSize prefSize = child->GetPrefSize(aState);
   327            nsSize minSize = child->GetMinSize(aState);
   328            nsSize maxSize = child->GetMaxSize(aState);
   329            prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize);
   331            AddMargin(child, prefSize);
   332            width = std::min(prefSize.width, originalClientRect.width);
   333            height = std::min(prefSize.height, originalClientRect.height);
   334         }
   335       }
   337       // Obtain the computed size along the axis of the box for this child from the computedBoxSize entry.  
   338       // We store the result in |width| for horizontal boxes and |height| for vertical boxes.
   339       if (frameState & NS_STATE_IS_HORIZONTAL)
   340         width = childComputedBoxSize->size;
   341       else
   342         height = childComputedBoxSize->size;
   344       // Adjust our x/y for the left/right spacing.
   345       if (frameState & NS_STATE_IS_HORIZONTAL) {
   346         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
   347           x += (childBoxSize->left);
   348         else
   349           x -= (childBoxSize->right);
   350       } else {
   351         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
   352           y += (childBoxSize->left);
   353         else
   354           y -= (childBoxSize->right);
   355       }
   357       nextX = x;
   358       nextY = y;
   360       // Now we build a child rect.
   361       nscoord rectX = x;
   362       nscoord rectY = y;
   363       if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
   364         if (frameState & NS_STATE_IS_HORIZONTAL)
   365           rectX -= width;
   366         else
   367           rectY -= height;
   368       }
   370       // We now create an accurate child rect based off our computed size information.
   371       nsRect childRect(rectX, rectY, width, height);
   373       // Sanity check against our clientRect.  It is possible that a child specified
   374       // a size that is too large to fit.  If that happens, then we have to grow
   375       // our client rect.  Remember, clientRect is not the total rect of the enclosing
   376       // box.  It currently holds our perception of how big the children needed to
   377       // be.
   378       if (childRect.width > clientRect.width)
   379         clientRect.width = childRect.width;
   381       if (childRect.height > clientRect.height)
   382         clientRect.height = childRect.height;
   384       // Either |nextX| or |nextY| is updated by this function call, according
   385       // to our axis.
   386       ComputeChildsNextPosition(aBox, x, y, nextX, nextY, childRect);
   388       // Now we further update our nextX/Y along our axis.
   389       // We also set childRect.y/x along the opposite axis appropriately for a
   390       // stretch alignment.  (Non-stretch alignment is handled below.)
   391       if (frameState & NS_STATE_IS_HORIZONTAL) {
   392         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
   393           nextX += (childBoxSize->right);
   394         else
   395           nextX -= (childBoxSize->left);
   396         childRect.y = originalClientRect.y;
   397       }
   398       else {
   399         if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
   400           nextY += (childBoxSize->right);
   401         else 
   402           nextY -= (childBoxSize->left);
   403         childRect.x = originalClientRect.x;
   404       }
   406       // If we encounter a completely bogus box size, we just leave this child completely
   407       // alone and continue through the loop to the next child.
   408       if (childBoxSize->bogus) 
   409       {
   410         childComputedBoxSize = childComputedBoxSize->next;
   411         childBoxSize = childBoxSize->next;
   412         count++;
   413         x = nextX;
   414         y = nextY;
   415         continue;
   416       }
   418       nsMargin margin(0,0,0,0);
   420       bool layout = true;
   422       // Deflate the rect of our child by its margin.
   423       child->GetMargin(margin);
   424       childRect.Deflate(margin);
   425       if (childRect.width < 0)
   426         childRect.width = 0;
   427       if (childRect.height < 0)
   428         childRect.height = 0;
   430       // Now we're trying to figure out if we have to lay out this child, i.e., to call
   431       // the child's Layout method.
   432       if (passes > 0) {
   433         layout = false;
   434       } else {
   435         // Always perform layout if we are dirty or have dirty children
   436         if (!NS_SUBTREE_DIRTY(child))
   437           layout = false;
   438       }
   440       nsRect oldRect(child->GetRect());
   442       // Non-stretch alignment will be handled in AlignChildren(), so don't
   443       // change child out-of-axis positions yet.
   444       if (!(frameState & NS_STATE_AUTO_STRETCH)) {
   445         if (frameState & NS_STATE_IS_HORIZONTAL) {
   446           childRect.y = oldRect.y;
   447         } else {
   448           childRect.x = oldRect.x;
   449         }
   450       }
   452       // We computed a childRect.  Now we want to set the bounds of the child to be that rect.
   453       // If our old rect is different, then we know our size changed and we cache that fact
   454       // in the |sizeChanged| variable.
   456       child->SetBounds(aState, childRect);
   457       bool sizeChanged = (childRect.width != oldRect.width ||
   458                             childRect.height != oldRect.height);
   460       if (sizeChanged) {
   461         // Our size is different.  Sanity check against our maximum allowed size to ensure
   462         // we didn't exceed it.
   463         nsSize minSize = child->GetMinSize(aState);
   464         nsSize maxSize = child->GetMaxSize(aState);
   465         maxSize = nsBox::BoundsCheckMinMax(minSize, maxSize);
   467         // make sure the size is in our max size.
   468         if (childRect.width > maxSize.width)
   469           childRect.width = maxSize.width;
   471         if (childRect.height > maxSize.height)
   472           childRect.height = maxSize.height;
   474         // set it again
   475         child->SetBounds(aState, childRect);
   476       }
   478       // If we already determined that layout was required or if our size has changed, then
   479       // we make sure to call layout on the child, since its children may need to be shifted
   480       // around as a result of the size change.
   481       if (layout || sizeChanged)
   482         child->Layout(aState);
   484       // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout. 
   485       // We have to check for this.
   486       nsRect newChildRect(child->GetRect());
   488       if (!newChildRect.IsEqualInterior(childRect)) {
   489 #ifdef DEBUG_GROW
   490         child->DumpBox(stdout);
   491         printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height);
   492 #endif
   493         newChildRect.Inflate(margin);
   494         childRect.Inflate(margin);
   496         // The child changed size during layout.  The ChildResized method handles this
   497         // scenario.
   498         ChildResized(aBox,
   499                      aState, 
   500                      child,
   501                      childBoxSize,
   502                      childComputedBoxSize,
   503                      boxSizes, 
   504                      computedBoxSizes, 
   505                      childRect,
   506                      newChildRect,
   507                      clientRect,
   508                      flexes,
   509                      finished);
   511         // We note that a child changed size, which means that another pass will be required.
   512         childResized = true;
   514         // Now that a child resized, it's entirely possible that OUR rect is too small.  Now we
   515         // ensure that |originalClientRect| is grown to accommodate the size of |clientRect|.
   516         if (clientRect.width > originalClientRect.width)
   517           originalClientRect.width = clientRect.width;
   519         if (clientRect.height > originalClientRect.height)
   520           originalClientRect.height = clientRect.height;
   522         if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
   523           // Our childRect had its XMost() or YMost() (depending on our layout
   524           // direction), positioned at a certain point.  Ensure that the
   525           // newChildRect satisfies the same constraint.  Note that this is
   526           // just equivalent to adjusting the x/y by the difference in
   527           // width/height between childRect and newChildRect.  So we don't need
   528           // to reaccount for the left and right of the box layout state again.
   529           if (frameState & NS_STATE_IS_HORIZONTAL)
   530             newChildRect.x = childRect.XMost() - newChildRect.width;
   531           else
   532             newChildRect.y = childRect.YMost() - newChildRect.height;
   533         }
   535         // If the child resized then recompute its position.
   536         ComputeChildsNextPosition(aBox, x, y, nextX, nextY, newChildRect);
   538         if (newChildRect.width >= margin.left + margin.right && newChildRect.height >= margin.top + margin.bottom) 
   539           newChildRect.Deflate(margin);
   541         if (childRect.width >= margin.left + margin.right && childRect.height >= margin.top + margin.bottom) 
   542           childRect.Deflate(margin);
   544         child->SetBounds(aState, newChildRect);
   546         // If we are the first box that changed size, then we don't need to do a second pass
   547         if (count == 0)
   548           finished = true;
   549       }
   551       // Now update our x/y finally.
   552       x = nextX;
   553       y = nextY;
   555       // Move to the next child.
   556       childComputedBoxSize = childComputedBoxSize->next;
   557       childBoxSize = childBoxSize->next;
   559       child = child->GetNextBox();
   560       count++;
   561     }
   563     // Sanity-checking code to ensure we don't do an infinite # of passes.
   564     passes++;
   565     NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!");
   566     if (passes > 10)
   567       break;
   568   } while (false == finished);
   570   // Get rid of our size lists.
   571   while(boxSizes)
   572   {
   573     nsBoxSize* toDelete = boxSizes;
   574     boxSizes = boxSizes->next;
   575     delete toDelete;
   576   }
   578   while(computedBoxSizes)
   579   {
   580     nsComputedBoxSize* toDelete = computedBoxSizes;
   581     computedBoxSizes = computedBoxSizes->next;
   582     delete toDelete;
   583   }
   585   if (childResized) {
   586     // See if one of our children forced us to get bigger
   587     nsRect tmpClientRect(originalClientRect);
   588     nsMargin bp(0,0,0,0);
   589     aBox->GetBorderAndPadding(bp);
   590     tmpClientRect.Inflate(bp);
   592     if (tmpClientRect.width > originalSize.width || tmpClientRect.height > originalSize.height)
   593     {
   594       // if it did reset our bounds.
   595       nsRect bounds(aBox->GetRect());
   596       if (tmpClientRect.width > originalSize.width)
   597         bounds.width = tmpClientRect.width;
   599       if (tmpClientRect.height > originalSize.height)
   600         bounds.height = tmpClientRect.height;
   602       aBox->SetBounds(aState, bounds);
   603     }
   604   }
   606   // Because our size grew, we now have to readjust because of box packing.  Repack
   607   // in order to update our x and y to the correct values.
   608   HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
   610   // Compare against our original x and y and only worry about adjusting the children if
   611   // we really did have to change the positions because of packing (typically for 'center'
   612   // or 'end' pack values).
   613   if (x != origX || y != origY) {
   614     nsIFrame* child = aBox->GetChildBox();
   616     // reposition all our children
   617     while (child) 
   618     {
   619       nsRect childRect(child->GetRect());
   620       childRect.x += (x - origX);
   621       childRect.y += (y - origY);
   622       child->SetBounds(aState, childRect);
   623       child = child->GetNextBox();
   624     }
   625   }
   627   // Perform out-of-axis alignment for non-stretch alignments
   628   if (!(frameState & NS_STATE_AUTO_STRETCH)) {
   629     AlignChildren(aBox, aState);
   630   }
   632   // That's it!  If you made it this far without having a nervous breakdown, 
   633   // congratulations!  Go get yourself a beer.
   634   return NS_OK;
   635 }
   637 void
   638 nsSprocketLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes)
   639 {
   640   // used for the equal size flag
   641   nscoord biggestPrefWidth = 0;
   642   nscoord biggestMinWidth = 0;
   643   nscoord smallestMaxWidth = NS_INTRINSICSIZE;
   645   nsFrameState frameState = nsFrameState(0);
   646   GetFrameState(aBox, frameState);
   648   //if (frameState & NS_STATE_CURRENTLY_IN_DEBUG)
   649   //   printf("In debug\n");
   651   aMinSize = 0;
   652   aMaxSize = NS_INTRINSICSIZE;
   654   bool isHorizontal;
   656   if (IsHorizontal(aBox))
   657      isHorizontal = true;
   658   else
   659      isHorizontal = false;
   661   // this is a nice little optimization
   662   // it turns out that if we only have 1 flexable child
   663   // then it does not matter what its preferred size is
   664   // there is nothing to flex it relative. This is great
   665   // because we can avoid asking for a preferred size in this
   666   // case. Why is this good? Well you might have html inside it
   667   // and asking html for its preferred size is rather expensive.
   668   // so we can just optimize it out this way.
   670   // set flexes
   671   nsIFrame* child = aBox->GetChildBox();
   673   aFlexes = 0;
   674   nsBoxSize* currentBox = nullptr;
   676 #if 0
   677   nsBoxSize* start = aBoxSizes;
   679   while(child)
   680   {
   681     // ok if we started with a list move down the list
   682     // until we reach the end. Then start looking at childen.
   683     // This feature is used extensively for Grid.
   684     nscoord flex = 0;    
   686     if (!start) {
   687       if (!currentBox) {
   688         aBoxSizes      = new (aState) nsBoxSize();
   689         currentBox      = aBoxSizes;
   690       } else {
   691         currentBox->next      = new (aState) nsBoxSize();
   692         currentBox      = currentBox->next;
   693       }
   696       flex = child->GetFlex(aState);
   698       currentBox->flex = flex;
   699       currentBox->collapsed = child->IsCollapsed();
   700     } else {
   701       flex = start->flex;
   702       start = start->next;
   703     }
   705     if (flex > 0) 
   706        aFlexes++;
   708     child = child->GetNextBox();
   709   }
   710 #endif
   712   // get pref, min, max
   713   child = aBox->GetChildBox();
   714   currentBox = aBoxSizes;
   715   nsBoxSize* last = nullptr;
   717   nscoord maxFlex = 0;
   718   int32_t childCount = 0;
   720   while(child)
   721   {
   722     while (currentBox && currentBox->bogus) {
   723       last = currentBox;
   724       currentBox = currentBox->next;
   725     }
   726     ++childCount;
   727     nsSize pref(0,0);
   728     nsSize minSize(0,0);
   729     nsSize maxSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
   730     nscoord ascent = 0;
   731     bool collapsed = child->IsCollapsed();
   733     if (!collapsed) {
   734     // only one flexible child? Cool we will just make its preferred size
   735     // 0 then and not even have to ask for it.
   736     //if (flexes != 1)  {
   738       pref = child->GetPrefSize(aState);
   739       minSize = child->GetMinSize(aState);
   740       maxSize = nsBox::BoundsCheckMinMax(minSize, child->GetMaxSize(aState));
   741       ascent = child->GetBoxAscent(aState);
   742       nsMargin margin;
   743       child->GetMargin(margin);
   744       ascent += margin.top;
   745     //}
   747       pref = nsBox::BoundsCheck(minSize, pref, maxSize);
   749       AddMargin(child, pref);
   750       AddMargin(child, minSize);
   751       AddMargin(child, maxSize);
   752     }
   754     if (!currentBox) {
   755       // create one.
   756       currentBox = new (aState) nsBoxSize();
   757       if (!aBoxSizes) {
   758         aBoxSizes = currentBox;
   759         last = aBoxSizes;
   760       } else {
   761         last->next = currentBox;
   762         last = currentBox;
   763       }
   765       nscoord minWidth;
   766       nscoord maxWidth;
   767       nscoord prefWidth;
   769       // get sizes from child
   770       if (isHorizontal) {
   771           minWidth  = minSize.width;
   772           maxWidth  = maxSize.width;
   773           prefWidth = pref.width;
   774       } else {
   775           minWidth = minSize.height;
   776           maxWidth = maxSize.height;
   777           prefWidth = pref.height;
   778       }
   780       nscoord flex = child->GetFlex(aState);
   782       // set them if you collapsed you are not flexible.
   783       if (collapsed) {
   784         currentBox->flex = 0;
   785       }
   786       else {
   787         if (flex > maxFlex) {
   788           maxFlex = flex;
   789         }
   790         currentBox->flex = flex;
   791       }
   793       // we specified all our children are equal size;
   794       if (frameState & NS_STATE_EQUAL_SIZE) {
   796         if (prefWidth > biggestPrefWidth) 
   797           biggestPrefWidth = prefWidth;
   799         if (minWidth > biggestMinWidth) 
   800           biggestMinWidth = minWidth;
   802         if (maxWidth < smallestMaxWidth) 
   803           smallestMaxWidth = maxWidth;
   804       } else { // not we can set our children right now.
   805         currentBox->pref    = prefWidth;
   806         currentBox->min     = minWidth;
   807         currentBox->max     = maxWidth;
   808       }
   810       NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,"Bad min, pref, max widths!");
   812     }
   814     if (!isHorizontal) {
   815       if (minSize.width > aMinSize)
   816         aMinSize = minSize.width;
   818       if (maxSize.width < aMaxSize)
   819         aMaxSize = maxSize.width;
   821     } else {
   822       if (minSize.height > aMinSize)
   823         aMinSize = minSize.height;
   825       if (maxSize.height < aMaxSize)
   826         aMaxSize = maxSize.height;
   827     }
   829     currentBox->collapsed = collapsed;
   830     aFlexes += currentBox->flex;
   832     child = child->GetNextBox();
   834     last = currentBox;
   835     currentBox = currentBox->next;
   837   }
   839   if (childCount > 0) {
   840     nscoord maxAllowedFlex = nscoord_MAX / childCount;
   842     if (MOZ_UNLIKELY(maxFlex > maxAllowedFlex)) {
   843       // clamp all the flexes
   844       currentBox = aBoxSizes;
   845       while (currentBox) {
   846         currentBox->flex = std::min(currentBox->flex, maxAllowedFlex);
   847         currentBox = currentBox->next;      
   848       }
   849     }
   850   }
   851 #ifdef DEBUG
   852   else {
   853     NS_ASSERTION(maxFlex == 0, "How did that happen?");
   854   }
   855 #endif
   857   // we specified all our children are equal size;
   858   if (frameState & NS_STATE_EQUAL_SIZE) {
   859     smallestMaxWidth = std::max(smallestMaxWidth, biggestMinWidth);
   860     biggestPrefWidth = nsBox::BoundsCheck(biggestMinWidth, biggestPrefWidth, smallestMaxWidth);
   862     currentBox = aBoxSizes;
   864     while(currentBox)
   865     {
   866       if (!currentBox->collapsed) {
   867         currentBox->pref = biggestPrefWidth;
   868         currentBox->min = biggestMinWidth;
   869         currentBox->max = smallestMaxWidth;
   870       } else {
   871         currentBox->pref = 0;
   872         currentBox->min = 0;
   873         currentBox->max = 0;
   874       }
   875       currentBox = currentBox->next;
   876     }
   877   }
   879 }
   881 void
   882 nsSprocketLayout::ComputeChildsNextPosition(nsIFrame* aBox, 
   883                                       const nscoord& aCurX, 
   884                                       const nscoord& aCurY, 
   885                                       nscoord& aNextX, 
   886                                       nscoord& aNextY, 
   887                                       const nsRect& aCurrentChildSize)
   888 {
   889   // Get the position along the box axis for the child.
   890   // The out-of-axis position is not set.
   891   nsFrameState frameState = nsFrameState(0);
   892   GetFrameState(aBox, frameState);
   894   if (IsHorizontal(aBox)) {
   895     // horizontal box's children.
   896     if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
   897       aNextX = aCurX + aCurrentChildSize.width;
   898     else
   899       aNextX = aCurX - aCurrentChildSize.width;
   901   } else {
   902     // vertical box's children.
   903     if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
   904       aNextY = aCurY + aCurrentChildSize.height;
   905     else
   906       aNextY = aCurY - aCurrentChildSize.height;
   907   }
   908 }
   910 void
   911 nsSprocketLayout::AlignChildren(nsIFrame* aBox,
   912                                 nsBoxLayoutState& aState)
   913 {
   914   nsFrameState frameState = nsFrameState(0);
   915   GetFrameState(aBox, frameState);
   916   bool isHorizontal = (frameState & NS_STATE_IS_HORIZONTAL) != 0;
   917   nsRect clientRect;
   918   aBox->GetClientRect(clientRect);
   920   NS_PRECONDITION(!(frameState & NS_STATE_AUTO_STRETCH),
   921                   "Only AlignChildren() with non-stretch alignment");
   923   // These are only calculated if needed
   924   nsIFrame::Halignment halign;
   925   nsIFrame::Valignment valign;
   926   nscoord maxAscent;
   927   bool isLTR;
   929   if (isHorizontal) {
   930     valign = aBox->GetVAlign();
   931     if (valign == nsBoxFrame::vAlign_BaseLine) {
   932       maxAscent = aBox->GetBoxAscent(aState);
   933     }
   934   } else {
   935     isLTR = GetFrameDirection(aBox) == NS_STYLE_DIRECTION_LTR;
   936     halign = aBox->GetHAlign();
   937   }
   939   nsIFrame* child = aBox->GetChildBox();
   940   while (child) {
   942     nsMargin margin;
   943     child->GetMargin(margin);
   944     nsRect childRect = child->GetRect();
   946     if (isHorizontal) {
   947       const nscoord startAlign = clientRect.y + margin.top;
   948       const nscoord endAlign =
   949         clientRect.YMost() - margin.bottom - childRect.height;
   951       nscoord y;
   952       switch (valign) {
   953         case nsBoxFrame::vAlign_Top:
   954           y = startAlign;
   955           break;
   956         case nsBoxFrame::vAlign_Middle:
   957           // Should this center the border box?
   958           // This centers the margin box, the historical behavior.
   959           y = (startAlign + endAlign) / 2;
   960           break;
   961         case nsBoxFrame::vAlign_Bottom:
   962           y = endAlign;
   963           break;
   964         case nsBoxFrame::vAlign_BaseLine:
   965           // Alignments don't force the box to grow (only sizes do),
   966           // so keep the children within the box.
   967           y = maxAscent - child->GetBoxAscent(aState);
   968           y = std::max(startAlign, y);
   969           y = std::min(y, endAlign);
   970           break;
   971       }
   973       childRect.y = y;
   975     } else { // vertical box
   976       const nscoord leftAlign = clientRect.x + margin.left;
   977       const nscoord rightAlign =
   978         clientRect.XMost() - margin.right - childRect.width;
   980       nscoord x;
   981       switch (halign) {
   982         case nsBoxFrame::hAlign_Left: // start
   983           x = isLTR ? leftAlign : rightAlign;
   984           break;
   985         case nsBoxFrame::hAlign_Center:
   986           x = (leftAlign + rightAlign) / 2;
   987           break;
   988         case nsBoxFrame::hAlign_Right: // end
   989           x = isLTR ? rightAlign : leftAlign;
   990           break;
   991       }
   993       childRect.x = x;
   994     }
   996     if (childRect.TopLeft() != child->GetPosition()) {
   997       child->SetBounds(aState, childRect);
   998     }
  1000     child = child->GetNextBox();
  1004 void
  1005 nsSprocketLayout::ChildResized(nsIFrame* aBox,
  1006                          nsBoxLayoutState& aState, 
  1007                          nsIFrame* aChild,
  1008                          nsBoxSize* aChildBoxSize,
  1009                          nsComputedBoxSize* aChildComputedSize,
  1010                          nsBoxSize* aBoxSizes, 
  1011                          nsComputedBoxSize* aComputedBoxSizes, 
  1012                          const nsRect& aChildLayoutRect, 
  1013                          nsRect& aChildActualRect, 
  1014                          nsRect& aContainingRect,
  1015                          int32_t aFlexes, 
  1016                          bool& aFinished)
  1019       nsRect childCurrentRect(aChildLayoutRect);
  1021       bool isHorizontal = IsHorizontal(aBox);
  1022       nscoord childLayoutWidth  = GET_WIDTH(aChildLayoutRect,isHorizontal);
  1023       nscoord& childActualWidth  = GET_WIDTH(aChildActualRect,isHorizontal);
  1024       nscoord& containingWidth   = GET_WIDTH(aContainingRect,isHorizontal);   
  1026       //nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal);
  1027       nscoord& childActualHeight = GET_HEIGHT(aChildActualRect,isHorizontal);
  1028       nscoord& containingHeight  = GET_HEIGHT(aContainingRect,isHorizontal);
  1030       bool recompute = false;
  1032       // if we are a horizontal box see if the child will fit inside us.
  1033       if ( childActualHeight > containingHeight) {
  1034             // if we are a horizontal box and the child is bigger than our height
  1036             // ok if the height changed then we need to reflow everyone but us at the new height
  1037             // so we will set the changed index to be us. And signal that we need a new pass.
  1039             nsSize min = aChild->GetMinSize(aState);            
  1040             nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetMaxSize(aState));
  1041             AddMargin(aChild, max);
  1043             if (isHorizontal)
  1044               childActualHeight = max.height < childActualHeight ? max.height : childActualHeight;
  1045             else
  1046               childActualHeight = max.width < childActualHeight ? max.width : childActualHeight;
  1048             // only set if it changes
  1049             if (childActualHeight > containingHeight) {
  1050                  containingHeight = childActualHeight;
  1052               // remember we do not need to clear the resized list because changing the height of a horizontal box
  1053               // will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me
  1054               // on this one.
  1055               aFinished = false;
  1057               // only recompute if there are flexes.
  1058               if (aFlexes > 0) {
  1059                 // relayout everything
  1060                 recompute = true;
  1061                 InvalidateComputedSizes(aComputedBoxSizes);
  1062                 nsComputedBoxSize* node = aComputedBoxSizes;
  1064                 while(node) {
  1065                   node->resized = false;
  1066                   node = node->next;
  1073       if (childActualWidth > childLayoutWidth) {
  1074             nsSize min = aChild->GetMinSize(aState);
  1075             nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetMaxSize(aState));
  1077             AddMargin(aChild, max);
  1079             // our width now becomes the new size
  1081             if (isHorizontal)
  1082               childActualWidth = max.width < childActualWidth ? max.width : childActualWidth;
  1083             else
  1084               childActualWidth = max.height < childActualWidth ? max.height : childActualWidth;
  1086             if (childActualWidth > childLayoutWidth) {
  1087                aChildComputedSize->size = childActualWidth;
  1088                aChildBoxSize->min = childActualWidth;
  1089                if (aChildBoxSize->pref < childActualWidth)
  1090                   aChildBoxSize->pref = childActualWidth;
  1091                if (aChildBoxSize->max < childActualWidth)
  1092                   aChildBoxSize->max = childActualWidth;
  1094               // if we have flexible elements with us then reflex things. Otherwise we can skip doing it.
  1095               if (aFlexes > 0) {
  1096                 InvalidateComputedSizes(aComputedBoxSizes);
  1098                 nsComputedBoxSize* node = aComputedBoxSizes;
  1099                 aChildComputedSize->resized = true;
  1101                 while(node) {
  1102                   if (node->resized)
  1103                       node->valid = true;
  1105                   node = node->next;
  1108                 recompute = true;
  1109                 aFinished = false;
  1110               } else {
  1111                 containingWidth += aChildComputedSize->size - childLayoutWidth;
  1116       if (recompute)
  1117             ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes, aComputedBoxSizes);
  1119       if (!childCurrentRect.IsEqualInterior(aChildActualRect)) {
  1120         // the childRect includes the margin
  1121         // make sure we remove it before setting 
  1122         // the bounds.
  1123         nsMargin margin(0,0,0,0);
  1124         aChild->GetMargin(margin);
  1125         nsRect rect(aChildActualRect);
  1126         if (rect.width >= margin.left + margin.right && rect.height >= margin.top + margin.bottom) 
  1127           rect.Deflate(margin);
  1129         aChild->SetBounds(aState, rect);
  1130         aChild->Layout(aState);
  1135 void
  1136 nsSprocketLayout::InvalidateComputedSizes(nsComputedBoxSize* aComputedBoxSizes)
  1138   while(aComputedBoxSizes) {
  1139       aComputedBoxSizes->valid = false;
  1140       aComputedBoxSizes = aComputedBoxSizes->next;
  1144 void
  1145 nsSprocketLayout::ComputeChildSizes(nsIFrame* aBox,
  1146                            nsBoxLayoutState& aState, 
  1147                            nscoord& aGivenSize, 
  1148                            nsBoxSize* aBoxSizes, 
  1149                            nsComputedBoxSize*& aComputedBoxSizes)
  1152   //nscoord onePixel = aState.PresContext()->IntScaledPixelsToTwips(1);
  1154   int32_t sizeRemaining            = aGivenSize;
  1155   int32_t spacerConstantsRemaining = 0;
  1157    // ----- calculate the spacers constants and the size remaining -----
  1159   if (!aComputedBoxSizes)
  1160       aComputedBoxSizes = new (aState) nsComputedBoxSize();
  1162   nsBoxSize*         boxSizes = aBoxSizes;
  1163   nsComputedBoxSize* computedBoxSizes = aComputedBoxSizes;
  1164   int32_t count = 0;
  1165   int32_t validCount = 0;
  1167   while (boxSizes) 
  1170     NS_ASSERTION((boxSizes->min <= boxSizes->pref && boxSizes->pref <= boxSizes->max),"bad pref, min, max size");
  1173      // ignore collapsed children
  1174   //  if (boxSizes->collapsed) 
  1175   //  {
  1176     //  computedBoxSizes->valid = true;
  1177     //  computedBoxSizes->size = boxSizes->pref;
  1178      // validCount++;
  1179   //      boxSizes->flex = 0;
  1180    // }// else {
  1182       if (computedBoxSizes->valid) { 
  1183         sizeRemaining -= computedBoxSizes->size;
  1184         validCount++;
  1185       } else {
  1186           if (boxSizes->flex == 0)
  1188             computedBoxSizes->valid = true;
  1189             computedBoxSizes->size = boxSizes->pref;
  1190             validCount++;
  1193           spacerConstantsRemaining += boxSizes->flex;
  1194           sizeRemaining -= boxSizes->pref;
  1197       sizeRemaining -= (boxSizes->left + boxSizes->right);
  1199     //} 
  1201     boxSizes = boxSizes->next;
  1203     if (boxSizes && !computedBoxSizes->next) 
  1204       computedBoxSizes->next = new (aState) nsComputedBoxSize();
  1206     computedBoxSizes = computedBoxSizes->next;
  1207     count++;
  1210   // everything accounted for?
  1211   if (validCount < count)
  1213     // ----- Ok we are give a size to fit into so stretch or squeeze to fit
  1214     // ----- Make sure we look at our min and max size
  1215     bool limit = true;
  1216     for (int pass=1; true == limit; pass++) 
  1218       limit = false;
  1219       boxSizes = aBoxSizes;
  1220       computedBoxSizes = aComputedBoxSizes;
  1222       while (boxSizes) { 
  1224         // ignore collapsed spacers
  1226    //    if (!boxSizes->collapsed) {
  1228           nscoord pref = 0;
  1229           nscoord max  = NS_INTRINSICSIZE;
  1230           nscoord min  = 0;
  1231           nscoord flex = 0;
  1233           pref = boxSizes->pref;
  1234           min  = boxSizes->min;
  1235           max  = boxSizes->max;
  1236           flex = boxSizes->flex;
  1238           // ----- look at our min and max limits make sure we aren't too small or too big -----
  1239           if (!computedBoxSizes->valid) {
  1240             int32_t newSize = pref + int32_t(int64_t(sizeRemaining) * flex / spacerConstantsRemaining);
  1242             if (newSize<=min) {
  1243               computedBoxSizes->size = min;
  1244               computedBoxSizes->valid = true;
  1245               spacerConstantsRemaining -= flex;
  1246               sizeRemaining += pref;
  1247               sizeRemaining -= min;
  1248               limit = true;
  1249             } else if (newSize>=max) {
  1250               computedBoxSizes->size = max;
  1251               computedBoxSizes->valid = true;
  1252               spacerConstantsRemaining -= flex;
  1253               sizeRemaining += pref;
  1254               sizeRemaining -= max;
  1255               limit = true;
  1258        // }
  1259         boxSizes         = boxSizes->next;
  1260         computedBoxSizes = computedBoxSizes->next;
  1265   // ---- once we have removed and min and max issues just stretch us out in the remaining space
  1266   // ---- or shrink us. Depends on the size remaining and the spacer constants
  1267   aGivenSize = 0;
  1268   boxSizes = aBoxSizes;
  1269   computedBoxSizes = aComputedBoxSizes;
  1271   while (boxSizes) { 
  1273     // ignore collapsed spacers
  1274   //  if (!(boxSizes && boxSizes->collapsed)) {
  1276       nscoord pref = 0;
  1277       nscoord flex = 0;
  1278       pref = boxSizes->pref;
  1279       flex = boxSizes->flex;
  1281       if (!computedBoxSizes->valid) {
  1282         computedBoxSizes->size = pref + int32_t(int64_t(sizeRemaining) * flex / spacerConstantsRemaining);
  1283         computedBoxSizes->valid = true;
  1286       aGivenSize += (boxSizes->left + boxSizes->right);
  1287       aGivenSize += computedBoxSizes->size;
  1289    // }
  1291     boxSizes         = boxSizes->next;
  1292     computedBoxSizes = computedBoxSizes->next;
  1297 nsSize
  1298 nsSprocketLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
  1300    nsSize vpref (0, 0); 
  1301    bool isHorizontal = IsHorizontal(aBox);
  1303    nscoord biggestPref = 0;
  1305    // run through all the children and get their min, max, and preferred sizes
  1306    // return us the size of the box
  1308    nsIFrame* child = aBox->GetChildBox();
  1309    nsFrameState frameState = nsFrameState(0);
  1310    GetFrameState(aBox, frameState);
  1311    bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
  1312    int32_t count = 0;
  1314    while (child) 
  1316       // ignore collapsed children
  1317       if (!child->IsCollapsed())
  1319         nsSize pref = child->GetPrefSize(aState);
  1320         AddMargin(child, pref);
  1322         if (isEqual) {
  1323           if (isHorizontal)
  1325             if (pref.width > biggestPref)
  1326               biggestPref = pref.width;
  1327           } else {
  1328             if (pref.height > biggestPref)
  1329               biggestPref = pref.height;
  1333         AddLargestSize(vpref, pref, isHorizontal);
  1334         count++;
  1337       child = child->GetNextBox();
  1340    if (isEqual) {
  1341       if (isHorizontal)
  1342          vpref.width = biggestPref*count;
  1343       else
  1344          vpref.height = biggestPref*count;
  1347    // now add our border and padding
  1348    AddBorderAndPadding(aBox, vpref);
  1350   return vpref;
  1353 nsSize
  1354 nsSprocketLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
  1356    nsSize minSize (0, 0);
  1357    bool isHorizontal = IsHorizontal(aBox);
  1359    nscoord biggestMin = 0;
  1362    // run through all the children and get their min, max, and preferred sizes
  1363    // return us the size of the box
  1365    nsIFrame* child = aBox->GetChildBox();
  1366    nsFrameState frameState = nsFrameState(0);
  1367    GetFrameState(aBox, frameState);
  1368    bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
  1369    int32_t count = 0;
  1371    while (child) 
  1373        // ignore collapsed children
  1374       if (!child->IsCollapsed())
  1376         nsSize min = child->GetMinSize(aState);
  1377         nsSize pref(0,0);
  1379         // if the child is not flexible then
  1380         // its min size is its pref size.
  1381         if (child->GetFlex(aState) == 0) {
  1382             pref = child->GetPrefSize(aState);
  1383             if (isHorizontal)
  1384                min.width = pref.width;
  1385             else
  1386                min.height = pref.height;
  1389         if (isEqual) {
  1390           if (isHorizontal)
  1392             if (min.width > biggestMin)
  1393               biggestMin = min.width;
  1394           } else {
  1395             if (min.height > biggestMin)
  1396               biggestMin = min.height;
  1400         AddMargin(child, min);
  1401         AddLargestSize(minSize, min, isHorizontal);
  1402         count++;
  1405       child = child->GetNextBox();
  1409    if (isEqual) {
  1410       if (isHorizontal)
  1411          minSize.width = biggestMin*count;
  1412       else
  1413          minSize.height = biggestMin*count;
  1416   // now add our border and padding
  1417   AddBorderAndPadding(aBox, minSize);
  1419   return minSize;
  1422 nsSize
  1423 nsSprocketLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
  1426   bool isHorizontal = IsHorizontal(aBox);
  1428    nscoord smallestMax = NS_INTRINSICSIZE;
  1429    nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
  1431    // run through all the children and get their min, max, and preferred sizes
  1432    // return us the size of the box
  1434    nsIFrame* child = aBox->GetChildBox();
  1435    nsFrameState frameState = nsFrameState(0);
  1436    GetFrameState(aBox, frameState);
  1437    bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
  1438    int32_t count = 0;
  1440    while (child) 
  1442       // ignore collapsed children
  1443       if (!child->IsCollapsed())
  1445         // if completely redefined don't even ask our child for its size.
  1446         nsSize min = child->GetMinSize(aState);
  1447         nsSize max = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
  1449         AddMargin(child, max);
  1450         AddSmallestSize(maxSize, max, isHorizontal);
  1452         if (isEqual) {
  1453           if (isHorizontal)
  1455             if (max.width < smallestMax)
  1456               smallestMax = max.width;
  1457           } else {
  1458             if (max.height < smallestMax)
  1459               smallestMax = max.height;
  1462         count++;
  1465       child = child->GetNextBox();
  1468    if (isEqual) {
  1469      if (isHorizontal) {
  1470          if (smallestMax != NS_INTRINSICSIZE)
  1471             maxSize.width = smallestMax*count;
  1472          else
  1473             maxSize.width = NS_INTRINSICSIZE;
  1474      } else {
  1475          if (smallestMax != NS_INTRINSICSIZE)
  1476             maxSize.height = smallestMax*count;
  1477          else
  1478             maxSize.height = NS_INTRINSICSIZE;
  1482   // now add our border and padding
  1483   AddBorderAndPadding(aBox, maxSize);
  1485   return maxSize;
  1489 nscoord
  1490 nsSprocketLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState)
  1492    nscoord vAscent = 0;
  1494    bool isHorizontal = IsHorizontal(aBox);
  1496    // run through all the children and get their min, max, and preferred sizes
  1497    // return us the size of the box
  1499    nsIFrame* child = aBox->GetChildBox();
  1501    while (child) 
  1503       // ignore collapsed children
  1504       //if (!child->IsCollapsed())
  1505       //{
  1506         // if completely redefined don't even ask our child for its size.
  1507         nscoord ascent = child->GetBoxAscent(aState);
  1509         nsMargin margin;
  1510         child->GetMargin(margin);
  1511         ascent += margin.top;
  1513         if (isHorizontal)
  1515           if (ascent > vAscent)
  1516             vAscent = ascent;
  1517         } else {
  1518           if (vAscent == 0)
  1519             vAscent = ascent;
  1521       //}
  1523       child = child->GetNextBox();      
  1526    nsMargin borderPadding;
  1527    aBox->GetBorderAndPadding(borderPadding);
  1529    return vAscent + borderPadding.top;
  1532 void
  1533 nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal)
  1535   if (aIsHorizontal)
  1537     if (aSize1.height < aSize2.height)
  1538        aSize1.height = aSize2.height;
  1539   } else {
  1540     if (aSize1.width < aSize2.width)
  1541        aSize1.width = aSize2.width;
  1545 void
  1546 nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal)
  1548   if (aIsHorizontal)
  1550     if (aSize1.height > aSize2.height)
  1551        aSize1.height = aSize2.height;
  1552   } else {
  1553     if (aSize1.width > aSize2.width)
  1554        aSize1.width = aSize2.width;
  1559 void
  1560 nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal)
  1562   if (aIsHorizontal)
  1563     AddCoord(aSize.width, aSizeToAdd.width);
  1564   else
  1565     AddCoord(aSize.height, aSizeToAdd.height);
  1567   SetLargestSize(aSize, aSizeToAdd, aIsHorizontal);
  1570 void
  1571 nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd)
  1573   if (aCoord != NS_INTRINSICSIZE) 
  1575     if (aCoordToAdd == NS_INTRINSICSIZE)
  1576       aCoord = aCoordToAdd;
  1577     else
  1578       aCoord += aCoordToAdd;
  1581 void
  1582 nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal)
  1584   if (aIsHorizontal)
  1585     AddCoord(aSize.width, aSizeToAdd.width);
  1586   else
  1587     AddCoord(aSize.height, aSizeToAdd.height);
  1589   SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal);
  1592 bool
  1593 nsSprocketLayout::GetDefaultFlex(int32_t& aFlex)
  1595     aFlex = 0;
  1596     return true;
  1599 nsComputedBoxSize::nsComputedBoxSize()
  1601   resized = false;
  1602   valid = false;
  1603   size = 0;
  1604   next = nullptr;
  1607 nsBoxSize::nsBoxSize()
  1609   pref = 0;
  1610   min = 0;
  1611   max = NS_INTRINSICSIZE;
  1612   collapsed = false;
  1613   left = 0;
  1614   right = 0;
  1615   flex = 0;
  1616   next = nullptr;
  1617   bogus = false;
  1621 void* 
  1622 nsBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
  1624   return mozilla::AutoStackArena::Allocate(sz);
  1628 void 
  1629 nsBoxSize::operator delete(void* aPtr, size_t sz)
  1634 void* 
  1635 nsComputedBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
  1637    return mozilla::AutoStackArena::Allocate(sz);
  1640 void 
  1641 nsComputedBoxSize::operator delete(void* aPtr, size_t sz)

mercurial