Fri, 16 Jan 2015 18:13:44 +0100
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();
1001 }
1002 }
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)
1018 {
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;
1067 }
1069 }
1070 }
1071 }
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;
1106 }
1108 recompute = true;
1109 aFinished = false;
1110 } else {
1111 containingWidth += aChildComputedSize->size - childLayoutWidth;
1112 }
1113 }
1114 }
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);
1131 }
1133 }
1135 void
1136 nsSprocketLayout::InvalidateComputedSizes(nsComputedBoxSize* aComputedBoxSizes)
1137 {
1138 while(aComputedBoxSizes) {
1139 aComputedBoxSizes->valid = false;
1140 aComputedBoxSizes = aComputedBoxSizes->next;
1141 }
1142 }
1144 void
1145 nsSprocketLayout::ComputeChildSizes(nsIFrame* aBox,
1146 nsBoxLayoutState& aState,
1147 nscoord& aGivenSize,
1148 nsBoxSize* aBoxSizes,
1149 nsComputedBoxSize*& aComputedBoxSizes)
1150 {
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)
1168 {
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)
1187 {
1188 computedBoxSizes->valid = true;
1189 computedBoxSizes->size = boxSizes->pref;
1190 validCount++;
1191 }
1193 spacerConstantsRemaining += boxSizes->flex;
1194 sizeRemaining -= boxSizes->pref;
1195 }
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++;
1208 }
1210 // everything accounted for?
1211 if (validCount < count)
1212 {
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++)
1217 {
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;
1256 }
1257 }
1258 // }
1259 boxSizes = boxSizes->next;
1260 computedBoxSizes = computedBoxSizes->next;
1261 }
1262 }
1263 }
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;
1284 }
1286 aGivenSize += (boxSizes->left + boxSizes->right);
1287 aGivenSize += computedBoxSizes->size;
1289 // }
1291 boxSizes = boxSizes->next;
1292 computedBoxSizes = computedBoxSizes->next;
1293 }
1294 }
1297 nsSize
1298 nsSprocketLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
1299 {
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)
1315 {
1316 // ignore collapsed children
1317 if (!child->IsCollapsed())
1318 {
1319 nsSize pref = child->GetPrefSize(aState);
1320 AddMargin(child, pref);
1322 if (isEqual) {
1323 if (isHorizontal)
1324 {
1325 if (pref.width > biggestPref)
1326 biggestPref = pref.width;
1327 } else {
1328 if (pref.height > biggestPref)
1329 biggestPref = pref.height;
1330 }
1331 }
1333 AddLargestSize(vpref, pref, isHorizontal);
1334 count++;
1335 }
1337 child = child->GetNextBox();
1338 }
1340 if (isEqual) {
1341 if (isHorizontal)
1342 vpref.width = biggestPref*count;
1343 else
1344 vpref.height = biggestPref*count;
1345 }
1347 // now add our border and padding
1348 AddBorderAndPadding(aBox, vpref);
1350 return vpref;
1351 }
1353 nsSize
1354 nsSprocketLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
1355 {
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)
1372 {
1373 // ignore collapsed children
1374 if (!child->IsCollapsed())
1375 {
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;
1387 }
1389 if (isEqual) {
1390 if (isHorizontal)
1391 {
1392 if (min.width > biggestMin)
1393 biggestMin = min.width;
1394 } else {
1395 if (min.height > biggestMin)
1396 biggestMin = min.height;
1397 }
1398 }
1400 AddMargin(child, min);
1401 AddLargestSize(minSize, min, isHorizontal);
1402 count++;
1403 }
1405 child = child->GetNextBox();
1406 }
1409 if (isEqual) {
1410 if (isHorizontal)
1411 minSize.width = biggestMin*count;
1412 else
1413 minSize.height = biggestMin*count;
1414 }
1416 // now add our border and padding
1417 AddBorderAndPadding(aBox, minSize);
1419 return minSize;
1420 }
1422 nsSize
1423 nsSprocketLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
1424 {
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)
1441 {
1442 // ignore collapsed children
1443 if (!child->IsCollapsed())
1444 {
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)
1454 {
1455 if (max.width < smallestMax)
1456 smallestMax = max.width;
1457 } else {
1458 if (max.height < smallestMax)
1459 smallestMax = max.height;
1460 }
1461 }
1462 count++;
1463 }
1465 child = child->GetNextBox();
1466 }
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;
1479 }
1480 }
1482 // now add our border and padding
1483 AddBorderAndPadding(aBox, maxSize);
1485 return maxSize;
1486 }
1489 nscoord
1490 nsSprocketLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState)
1491 {
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)
1502 {
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)
1514 {
1515 if (ascent > vAscent)
1516 vAscent = ascent;
1517 } else {
1518 if (vAscent == 0)
1519 vAscent = ascent;
1520 }
1521 //}
1523 child = child->GetNextBox();
1524 }
1526 nsMargin borderPadding;
1527 aBox->GetBorderAndPadding(borderPadding);
1529 return vAscent + borderPadding.top;
1530 }
1532 void
1533 nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal)
1534 {
1535 if (aIsHorizontal)
1536 {
1537 if (aSize1.height < aSize2.height)
1538 aSize1.height = aSize2.height;
1539 } else {
1540 if (aSize1.width < aSize2.width)
1541 aSize1.width = aSize2.width;
1542 }
1543 }
1545 void
1546 nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal)
1547 {
1548 if (aIsHorizontal)
1549 {
1550 if (aSize1.height > aSize2.height)
1551 aSize1.height = aSize2.height;
1552 } else {
1553 if (aSize1.width > aSize2.width)
1554 aSize1.width = aSize2.width;
1556 }
1557 }
1559 void
1560 nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal)
1561 {
1562 if (aIsHorizontal)
1563 AddCoord(aSize.width, aSizeToAdd.width);
1564 else
1565 AddCoord(aSize.height, aSizeToAdd.height);
1567 SetLargestSize(aSize, aSizeToAdd, aIsHorizontal);
1568 }
1570 void
1571 nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd)
1572 {
1573 if (aCoord != NS_INTRINSICSIZE)
1574 {
1575 if (aCoordToAdd == NS_INTRINSICSIZE)
1576 aCoord = aCoordToAdd;
1577 else
1578 aCoord += aCoordToAdd;
1579 }
1580 }
1581 void
1582 nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal)
1583 {
1584 if (aIsHorizontal)
1585 AddCoord(aSize.width, aSizeToAdd.width);
1586 else
1587 AddCoord(aSize.height, aSizeToAdd.height);
1589 SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal);
1590 }
1592 bool
1593 nsSprocketLayout::GetDefaultFlex(int32_t& aFlex)
1594 {
1595 aFlex = 0;
1596 return true;
1597 }
1599 nsComputedBoxSize::nsComputedBoxSize()
1600 {
1601 resized = false;
1602 valid = false;
1603 size = 0;
1604 next = nullptr;
1605 }
1607 nsBoxSize::nsBoxSize()
1608 {
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;
1618 }
1621 void*
1622 nsBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
1623 {
1624 return mozilla::AutoStackArena::Allocate(sz);
1625 }
1628 void
1629 nsBoxSize::operator delete(void* aPtr, size_t sz)
1630 {
1631 }
1634 void*
1635 nsComputedBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW
1636 {
1637 return mozilla::AutoStackArena::Allocate(sz);
1638 }
1640 void
1641 nsComputedBoxSize::operator delete(void* aPtr, size_t sz)
1642 {
1643 }