Bug 1675375 Part 7: Update expectations in helper_hittest_clippath.html. r=botond
[gecko.git] / layout / xul / nsSprocketLayout.cpp
blob186894ce269364a860b4476c3509e9099f0f1bef
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 //
8 // Eric Vaughan
9 // Netscape Communications
11 // See documentation in associated header file
14 #include "nsBoxLayoutState.h"
15 #include "nsSprocketLayout.h"
16 #include "nsPresContext.h"
17 #include "nsCOMPtr.h"
18 #include "nsIContent.h"
19 #include "nsContainerFrame.h"
20 #include "nsBoxFrame.h"
21 #include "StackArena.h"
22 #include "mozilla/Likely.h"
23 #include "mozilla/CSSOrderAwareFrameIterator.h"
24 #include <algorithm>
26 using mozilla::StyleDirection;
27 using namespace mozilla;
29 nsBoxLayout* nsSprocketLayout::gInstance = nullptr;
31 static Maybe<CSSOrderAwareFrameIterator> IterFor(nsIFrame* aBoxFrame) {
32 Maybe<CSSOrderAwareFrameIterator> ret;
33 if (aBoxFrame->IsXULBoxFrame()) {
34 ret.emplace(aBoxFrame, mozilla::layout::kPrincipalList,
35 CSSOrderAwareFrameIterator::ChildFilter::IncludeAll,
36 CSSOrderAwareFrameIterator::OrderState::Unknown,
37 CSSOrderAwareFrameIterator::OrderingProperty::BoxOrdinalGroup);
39 return ret;
42 nsresult NS_NewSprocketLayout(nsCOMPtr<nsBoxLayout>& aNewLayout) {
43 if (!nsSprocketLayout::gInstance) {
44 nsSprocketLayout::gInstance = new nsSprocketLayout();
45 NS_IF_ADDREF(nsSprocketLayout::gInstance);
47 // we have not instance variables so just return our static one.
48 aNewLayout = nsSprocketLayout::gInstance;
49 return NS_OK;
52 /*static*/
53 void nsSprocketLayout::Shutdown() { NS_IF_RELEASE(gInstance); }
55 nsSprocketLayout::nsSprocketLayout() = default;
57 bool nsSprocketLayout::IsXULHorizontal(nsIFrame* aBox) {
58 return aBox->HasAnyStateBits(NS_STATE_IS_HORIZONTAL);
61 void nsSprocketLayout::GetFrameState(nsIFrame* aBox, nsFrameState& aState) {
62 aState = aBox->GetStateBits();
65 static StyleDirection GetFrameDirection(nsIFrame* aBox) {
66 return aBox->StyleVisibility()->mDirection;
69 static void HandleBoxPack(nsIFrame* aBox, const nsFrameState& aFrameState,
70 nscoord& aX, nscoord& aY, const nsRect& aOriginalRect,
71 const nsRect& aClientRect) {
72 // In the normal direction we lay out our kids in the positive direction
73 // (e.g., |x| will get bigger for a horizontal box, and |y| will get bigger
74 // for a vertical box). In the reverse direction, the opposite is true. We'll
75 // be laying out each child at a smaller |x| or |y|.
76 StyleDirection frameDirection = GetFrameDirection(aBox);
78 if (aFrameState & NS_STATE_IS_HORIZONTAL) {
79 if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
80 // The normal direction. |x| increases as we move through our children.
81 aX = aClientRect.x;
82 } else {
83 // The reverse direction. |x| decreases as we move through our children.
84 aX = aClientRect.x + aOriginalRect.width;
86 // |y| is always in the normal direction in horizontal boxes
87 aY = aClientRect.y;
88 } else {
89 // take direction property into account for |x| in vertical boxes
90 if (frameDirection == StyleDirection::Ltr) {
91 // The normal direction. |x| increases as we move through our children.
92 aX = aClientRect.x;
93 } else {
94 // The reverse direction. |x| decreases as we move through our children.
95 aX = aClientRect.x + aOriginalRect.width;
97 if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) {
98 // The normal direction. |y| increases as we move through our children.
99 aY = aClientRect.y;
100 } else {
101 // The reverse direction. |y| decreases as we move through our children.
102 aY = aClientRect.y + aOriginalRect.height;
106 // Get our pack/alignment information.
107 nsIFrame::Halignment halign = aBox->GetXULHAlign();
108 nsIFrame::Valignment valign = aBox->GetXULVAlign();
110 // The following code handles box PACKING. Packing comes into play in the
111 // case where the computed size for all of our children (now stored in our
112 // client rect) is smaller than the size available for the box (stored in
113 // |aOriginalRect|).
115 // Here we adjust our |x| and |y| variables accordingly so that we start at
116 // the beginning, middle, or end of the box.
118 // XXXdwh JUSTIFY needs to be implemented!
119 if (aFrameState & NS_STATE_IS_HORIZONTAL) {
120 switch (halign) {
121 case nsBoxFrame::hAlign_Left:
122 break; // Nothing to do. The default initialized us properly.
124 case nsBoxFrame::hAlign_Center:
125 if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
126 aX += (aOriginalRect.width - aClientRect.width) / 2;
127 else
128 aX -= (aOriginalRect.width - aClientRect.width) / 2;
129 break;
131 case nsBoxFrame::hAlign_Right:
132 if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
133 aX += (aOriginalRect.width - aClientRect.width);
134 else
135 aX -= (aOriginalRect.width - aClientRect.width);
136 break; // Nothing to do for the reverse dir. The default initialized
137 // us properly.
139 } else {
140 switch (valign) {
141 case nsBoxFrame::vAlign_Top:
142 case nsBoxFrame::vAlign_BaseLine: // This value is technically impossible
143 // to specify for pack.
144 break; // Don't do anything. We were initialized correctly.
146 case nsBoxFrame::vAlign_Middle:
147 if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
148 aY += (aOriginalRect.height - aClientRect.height) / 2;
149 else
150 aY -= (aOriginalRect.height - aClientRect.height) / 2;
151 break;
153 case nsBoxFrame::vAlign_Bottom:
154 if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL)
155 aY += (aOriginalRect.height - aClientRect.height);
156 else
157 aY -= (aOriginalRect.height - aClientRect.height);
158 break;
163 NS_IMETHODIMP
164 nsSprocketLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) {
165 // See if we are collapsed. If we are, then simply iterate over all our
166 // children and give them a rect of 0 width and height.
167 if (aBox->IsXULCollapsed()) {
168 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
169 nsBoxFrame::LayoutChildAt(aState, iter->get(), nsRect(0, 0, 0, 0));
171 return NS_OK;
174 nsBoxLayoutState::AutoReflowDepth depth(aState);
175 mozilla::AutoStackArena arena;
177 // ----- figure out our size ----------
178 const nsSize originalSize = aBox->GetSize();
180 // -- make sure we remove our border and padding ----
181 nsRect clientRect;
182 aBox->GetXULClientRect(clientRect);
184 // |originalClientRect| represents the rect of the entire box (excluding
185 // borders and padding). We store it here because we're going to use
186 // |clientRect| to hold the required size for all our kids. As an example,
187 // consider an hbox with a specified width of 300. If the kids total only 150
188 // pixels of width, then we have 150 pixels left over. |clientRect| is going
189 // to hold a width of 150 and is going to be adjusted based off the value of
190 // the PACK property. If flexible objects are in the box, then the two rects
191 // will match.
192 nsRect originalClientRect(clientRect);
194 // The frame state contains cached knowledge about our box, such as our
195 // orientation and direction.
196 nsFrameState frameState = nsFrameState(0);
197 GetFrameState(aBox, frameState);
199 // Build a list of our children's desired sizes and computed sizes
200 nsBoxSize* boxSizes = nullptr;
201 nsComputedBoxSize* computedBoxSizes = nullptr;
203 nscoord min = 0;
204 nscoord max = 0;
205 int32_t flexes = 0;
206 PopulateBoxSizes(aBox, aState, boxSizes, min, max, flexes);
208 // The |size| variable will hold the total size of children along the axis of
209 // the box. Continuing with the example begun in the comment above, size
210 // would be 150 pixels.
211 nscoord size = clientRect.width;
212 if (!IsXULHorizontal(aBox)) size = clientRect.height;
213 ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes);
215 // After the call to ComputeChildSizes, the |size| variable contains the
216 // total required size of all the children. We adjust our clientRect in the
217 // appropriate dimension to match this size. In our example, we now assign
218 // 150 pixels into the clientRect.width.
220 // The variables |min| and |max| hold the minimum required size box must be
221 // in the OPPOSITE orientation, e.g., for a horizontal box, |min| is the
222 // minimum height we require to enclose our children, and |max| is the maximum
223 // height required to enclose our children.
224 if (IsXULHorizontal(aBox)) {
225 clientRect.width = size;
226 if (clientRect.height < min) clientRect.height = min;
228 if (frameState & NS_STATE_AUTO_STRETCH) {
229 if (clientRect.height > max) clientRect.height = max;
231 } else {
232 clientRect.height = size;
233 if (clientRect.width < min) clientRect.width = min;
235 if (frameState & NS_STATE_AUTO_STRETCH) {
236 if (clientRect.width > max) clientRect.width = max;
240 // With the sizes computed, now it's time to lay out our children.
241 bool finished;
242 nscoord passes = 0;
244 // We flow children at their preferred locations (along with the appropriate
245 // computed flex). After we flow a child, it is possible that the child will
246 // change its size. If/when this happens, we have to do another pass.
247 // Typically only 2 passes are required, but the code is prepared to do as
248 // many passes as are necessary to achieve equilibrium.
249 nscoord x = 0;
250 nscoord y = 0;
251 nscoord origX = 0;
252 nscoord origY = 0;
254 // |childResized| lets us know if a child changed its size after we attempted
255 // to lay it out at the specified size. If this happens, we usually have to
256 // do another pass.
257 bool childResized = false;
259 // |passes| stores our number of passes. If for any reason we end up doing
260 // more than, say, 10 passes, we assert to indicate that something is
261 // seriously screwed up.
262 passes = 0;
263 do {
264 // Always assume that we're done. This will change if, for example,
265 // children don't stay the same size after being flowed.
266 finished = true;
268 // Handle box packing.
269 HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
271 // Now that packing is taken care of we set up a few additional
272 // tracking variables.
273 origX = x;
274 origY = y;
276 // Now we iterate over our box children and our box size lists in
277 // parallel. For each child, we look at its sizes and figure out
278 // where to place it.
279 nsComputedBoxSize* childComputedBoxSize = computedBoxSizes;
280 nsBoxSize* childBoxSize = boxSizes;
282 auto iter = IterFor(aBox);
283 int32_t count = 0;
284 while ((iter && !iter->AtEnd()) || (childBoxSize && childBoxSize->bogus)) {
285 // If for some reason, our lists are not the same length, we guard
286 // by bailing out of the loop.
287 if (childBoxSize == nullptr) {
288 MOZ_ASSERT_UNREACHABLE("Lists not the same length.");
289 break;
292 nscoord width = clientRect.width;
293 nscoord height = clientRect.height;
295 if (!childBoxSize->bogus) {
296 nsIFrame* child = iter->get();
298 // We have a valid box size entry. This entry already contains
299 // information about our sizes along the axis of the box (e.g., widths
300 // in a horizontal box). If our default ALIGN is not stretch, however,
301 // then we also need to know the child's size along the opposite axis.
302 if (!(frameState & NS_STATE_AUTO_STRETCH)) {
303 nsSize prefSize = child->GetXULPrefSize(aState);
304 nsSize minSize = child->GetXULMinSize(aState);
305 nsSize maxSize = child->GetXULMaxSize(aState);
306 prefSize = nsIFrame::XULBoundsCheck(minSize, prefSize, maxSize);
308 AddXULMargin(child, prefSize);
309 width = std::min(prefSize.width, originalClientRect.width);
310 height = std::min(prefSize.height, originalClientRect.height);
314 // Obtain the computed size along the axis of the box for this child from
315 // the computedBoxSize entry. We store the result in |width| for
316 // horizontal boxes and |height| for vertical boxes.
317 if (frameState & NS_STATE_IS_HORIZONTAL)
318 width = childComputedBoxSize->size;
319 else
320 height = childComputedBoxSize->size;
322 // Adjust our x/y for the left/right spacing.
323 if (frameState & NS_STATE_IS_HORIZONTAL) {
324 if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
325 x += (childBoxSize->left);
326 else
327 x -= (childBoxSize->right);
328 } else {
329 if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
330 y += (childBoxSize->left);
331 else
332 y -= (childBoxSize->right);
335 // Now we build a child rect.
336 nscoord rectX = x;
337 nscoord rectY = y;
338 if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
339 if (frameState & NS_STATE_IS_HORIZONTAL)
340 rectX -= width;
341 else
342 rectY -= height;
345 // We now create an accurate child rect based off our computed size
346 // information.
347 nsRect childRect(rectX, rectY, width, height);
349 // Sanity check against our clientRect. It is possible that a child
350 // specified a size that is too large to fit. If that happens, then we
351 // have to grow our client rect. Remember, clientRect is not the total
352 // rect of the enclosing box. It currently holds our perception of how
353 // big the children needed to be.
354 if (childRect.width > clientRect.width)
355 clientRect.width = childRect.width;
357 if (childRect.height > clientRect.height)
358 clientRect.height = childRect.height;
360 // Either |nextX| or |nextY| is updated by this function call, according
361 // to our axis.
362 nscoord nextX = x;
363 nscoord nextY = y;
365 ComputeChildsNextPosition(aBox, x, y, nextX, nextY, childRect);
367 // Now we further update our nextX/Y along our axis.
368 // We also set childRect.y/x along the opposite axis appropriately for a
369 // stretch alignment. (Non-stretch alignment is handled below.)
370 if (frameState & NS_STATE_IS_HORIZONTAL) {
371 if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
372 nextX += (childBoxSize->right);
373 else
374 nextX -= (childBoxSize->left);
375 childRect.y = originalClientRect.y;
376 } else {
377 if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
378 nextY += (childBoxSize->right);
379 else
380 nextY -= (childBoxSize->left);
381 if (GetFrameDirection(aBox) == StyleDirection::Ltr) {
382 childRect.x = originalClientRect.x;
383 } else {
384 // keep the right edge of the box the same
385 childRect.x =
386 clientRect.x + originalClientRect.width - childRect.width;
390 // If we encounter a completely bogus box size, we just leave this child
391 // completely alone and continue through the loop to the next child.
392 if (childBoxSize->bogus) {
393 childComputedBoxSize = childComputedBoxSize->next;
394 childBoxSize = childBoxSize->next;
395 count++;
396 x = nextX;
397 y = nextY;
398 // FIXME(emilio): shouldn't this update `child` / `iter`? This looks
399 // broken.
400 continue;
403 nsIFrame* child = iter->get();
404 nsMargin margin(0, 0, 0, 0);
406 bool layout = true;
408 // Deflate the rect of our child by its margin.
409 child->GetXULMargin(margin);
410 childRect.Deflate(margin);
411 if (childRect.width < 0) childRect.width = 0;
412 if (childRect.height < 0) childRect.height = 0;
414 // Now we're trying to figure out if we have to lay out this child, i.e.,
415 // to call the child's XULLayout method.
416 if (passes > 0) {
417 layout = false;
418 } else {
419 // Always perform layout if we are dirty or have dirty children
420 if (!child->IsSubtreeDirty()) {
421 layout = false;
425 nsRect oldRect(child->GetRect());
427 // Non-stretch alignment will be handled in AlignChildren(), so don't
428 // change child out-of-axis positions yet.
429 if (!(frameState & NS_STATE_AUTO_STRETCH)) {
430 if (frameState & NS_STATE_IS_HORIZONTAL) {
431 childRect.y = oldRect.y;
432 } else {
433 childRect.x = oldRect.x;
437 // We computed a childRect. Now we want to set the bounds of the child to
438 // be that rect. If our old rect is different, then we know our size
439 // changed and we cache that fact in the |sizeChanged| variable.
441 child->SetXULBounds(aState, childRect);
442 bool sizeChanged = (childRect.width != oldRect.width ||
443 childRect.height != oldRect.height);
445 if (sizeChanged) {
446 // Our size is different. Sanity check against our maximum allowed size
447 // to ensure we didn't exceed it.
448 nsSize minSize = child->GetXULMinSize(aState);
449 nsSize maxSize = child->GetXULMaxSize(aState);
450 maxSize = nsIFrame::XULBoundsCheckMinMax(minSize, maxSize);
452 // make sure the size is in our max size.
453 if (childRect.width > maxSize.width) childRect.width = maxSize.width;
455 if (childRect.height > maxSize.height)
456 childRect.height = maxSize.height;
458 // set it again
459 child->SetXULBounds(aState, childRect);
462 // If we already determined that layout was required or if our size has
463 // changed, then we make sure to call layout on the child, since its
464 // children may need to be shifted around as a result of the size change.
465 if (layout || sizeChanged) child->XULLayout(aState);
467 // If the child was a block or inline (e.g., HTML) it may have changed its
468 // rect *during* layout. We have to check for this.
469 nsRect newChildRect(child->GetRect());
471 if (!newChildRect.IsEqualInterior(childRect)) {
472 #ifdef DEBUG_GROW
473 printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width,
474 childRect.height, newChildRect.width, newChildRect.height);
475 #endif
476 newChildRect.Inflate(margin);
477 childRect.Inflate(margin);
479 // The child changed size during layout. The ChildResized method
480 // handles this scenario.
481 ChildResized(aBox, aState, child, childBoxSize, childComputedBoxSize,
482 boxSizes, computedBoxSizes, childRect, newChildRect,
483 clientRect, flexes, finished);
485 // We note that a child changed size, which means that another pass will
486 // be required.
487 childResized = true;
489 // Now that a child resized, it's entirely possible that OUR rect is too
490 // small. Now we ensure that |originalClientRect| is grown to
491 // accommodate the size of |clientRect|.
492 if (clientRect.width > originalClientRect.width)
493 originalClientRect.width = clientRect.width;
495 if (clientRect.height > originalClientRect.height)
496 originalClientRect.height = clientRect.height;
498 if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
499 // Our childRect had its XMost() or YMost() (depending on our layout
500 // direction), positioned at a certain point. Ensure that the
501 // newChildRect satisfies the same constraint. Note that this is
502 // just equivalent to adjusting the x/y by the difference in
503 // width/height between childRect and newChildRect. So we don't need
504 // to reaccount for the left and right of the box layout state again.
505 if (frameState & NS_STATE_IS_HORIZONTAL)
506 newChildRect.x = childRect.XMost() - newChildRect.width;
507 else
508 newChildRect.y = childRect.YMost() - newChildRect.height;
511 if (!(frameState & NS_STATE_IS_HORIZONTAL)) {
512 if (GetFrameDirection(aBox) != StyleDirection::Ltr) {
513 // keep the right edge the same
514 newChildRect.x = childRect.XMost() - newChildRect.width;
518 // If the child resized then recompute its position.
519 ComputeChildsNextPosition(aBox, x, y, nextX, nextY, newChildRect);
521 if (newChildRect.width >= margin.left + margin.right &&
522 newChildRect.height >= margin.top + margin.bottom)
523 newChildRect.Deflate(margin);
525 if (childRect.width >= margin.left + margin.right &&
526 childRect.height >= margin.top + margin.bottom)
527 childRect.Deflate(margin);
529 child->SetXULBounds(aState, newChildRect);
531 // If we are the first box that changed size, then we don't need to do a
532 // second pass
533 if (count == 0) finished = true;
536 // Now update our x/y finally.
537 x = nextX;
538 y = nextY;
540 // Move to the next child.
541 childComputedBoxSize = childComputedBoxSize->next;
542 childBoxSize = childBoxSize->next;
544 iter->Next();
545 count++;
548 // Sanity-checking code to ensure we don't do an infinite # of passes.
549 passes++;
550 NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!");
551 if (passes >= 10) break;
552 } while (false == finished);
554 // Get rid of our size lists.
555 while (boxSizes) {
556 nsBoxSize* toDelete = boxSizes;
557 boxSizes = boxSizes->next;
558 delete toDelete;
561 while (computedBoxSizes) {
562 nsComputedBoxSize* toDelete = computedBoxSizes;
563 computedBoxSizes = computedBoxSizes->next;
564 delete toDelete;
567 if (childResized) {
568 // See if one of our children forced us to get bigger
569 nsRect tmpClientRect(originalClientRect);
570 nsMargin bp(0, 0, 0, 0);
571 aBox->GetXULBorderAndPadding(bp);
572 tmpClientRect.Inflate(bp);
574 if (tmpClientRect.width > originalSize.width ||
575 tmpClientRect.height > originalSize.height) {
576 // if it did reset our bounds.
577 nsRect bounds(aBox->GetRect());
578 if (tmpClientRect.width > originalSize.width)
579 bounds.width = tmpClientRect.width;
581 if (tmpClientRect.height > originalSize.height)
582 bounds.height = tmpClientRect.height;
584 aBox->SetXULBounds(aState, bounds);
588 // Because our size grew, we now have to readjust because of box packing.
589 // Repack in order to update our x and y to the correct values.
590 HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);
592 // Compare against our original x and y and only worry about adjusting the
593 // children if we really did have to change the positions because of packing
594 // (typically for 'center' or 'end' pack values).
595 if (x != origX || y != origY) {
596 // reposition all our children
597 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
598 nsIFrame* child = iter->get();
599 nsRect childRect(child->GetRect());
600 childRect.x += (x - origX);
601 childRect.y += (y - origY);
602 child->SetXULBounds(aState, childRect);
606 // Perform out-of-axis alignment for non-stretch alignments
607 if (!(frameState & NS_STATE_AUTO_STRETCH)) {
608 AlignChildren(aBox, aState);
611 // That's it! If you made it this far without having a nervous breakdown,
612 // congratulations! Go get yourself a beer.
613 return NS_OK;
616 void nsSprocketLayout::PopulateBoxSizes(nsIFrame* aBox,
617 nsBoxLayoutState& aState,
618 nsBoxSize*& aBoxSizes,
619 nscoord& aMinSize, nscoord& aMaxSize,
620 int32_t& aFlexes) {
621 // used for the equal size flag
622 nscoord biggestPrefWidth = 0;
623 nscoord biggestMinWidth = 0;
624 nscoord smallestMaxWidth = NS_UNCONSTRAINEDSIZE;
626 nsFrameState frameState = nsFrameState(0);
627 GetFrameState(aBox, frameState);
629 aMinSize = 0;
630 aMaxSize = NS_UNCONSTRAINEDSIZE;
632 bool isHorizontal;
634 if (IsXULHorizontal(aBox))
635 isHorizontal = true;
636 else
637 isHorizontal = false;
639 // this is a nice little optimization
640 // it turns out that if we only have 1 flexable child
641 // then it does not matter what its preferred size is
642 // there is nothing to flex it relative. This is great
643 // because we can avoid asking for a preferred size in this
644 // case. Why is this good? Well you might have html inside it
645 // and asking html for its preferred size is rather expensive.
646 // so we can just optimize it out this way.
648 // set flexes
649 aFlexes = 0;
650 nsBoxSize* currentBox = aBoxSizes;
651 nsBoxSize* last = nullptr;
653 nscoord maxFlex = 0;
654 int32_t childCount = 0;
656 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
657 nsIFrame* child = iter->get();
658 while (currentBox && currentBox->bogus) {
659 last = currentBox;
660 currentBox = currentBox->next;
662 ++childCount;
663 nsSize pref(0, 0);
664 nsSize minSize(0, 0);
665 nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
666 bool collapsed = child->IsXULCollapsed();
668 if (!collapsed) {
669 // only one flexible child? Cool we will just make its preferred size
670 // 0 then and not even have to ask for it.
671 // if (flexes != 1) {
673 pref = child->GetXULPrefSize(aState);
674 minSize = child->GetXULMinSize(aState);
675 maxSize =
676 nsIFrame::XULBoundsCheckMinMax(minSize, child->GetXULMaxSize(aState));
677 child->GetXULBoxAscent(aState);
680 pref = nsIFrame::XULBoundsCheck(minSize, pref, maxSize);
682 AddXULMargin(child, pref);
683 AddXULMargin(child, minSize);
684 AddXULMargin(child, maxSize);
687 if (!currentBox) {
688 // create one.
689 currentBox = new (aState) nsBoxSize();
690 if (!aBoxSizes) {
691 aBoxSizes = currentBox;
692 last = aBoxSizes;
693 } else {
694 last->next = currentBox;
695 last = currentBox;
698 nscoord minWidth;
699 nscoord maxWidth;
700 nscoord prefWidth;
702 // get sizes from child
703 if (isHorizontal) {
704 minWidth = minSize.width;
705 maxWidth = maxSize.width;
706 prefWidth = pref.width;
707 } else {
708 minWidth = minSize.height;
709 maxWidth = maxSize.height;
710 prefWidth = pref.height;
713 nscoord flex = child->GetXULFlex();
715 // set them if you collapsed you are not flexible.
716 if (collapsed) {
717 currentBox->flex = 0;
718 } else {
719 if (flex > maxFlex) {
720 maxFlex = flex;
722 currentBox->flex = flex;
725 // we specified all our children are equal size;
726 if (frameState & NS_STATE_EQUAL_SIZE) {
727 if (prefWidth > biggestPrefWidth) biggestPrefWidth = prefWidth;
729 if (minWidth > biggestMinWidth) biggestMinWidth = minWidth;
731 if (maxWidth < smallestMaxWidth) smallestMaxWidth = maxWidth;
732 } else { // not we can set our children right now.
733 currentBox->pref = prefWidth;
734 currentBox->min = minWidth;
735 currentBox->max = maxWidth;
738 NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,
739 "Bad min, pref, max widths!");
742 if (!isHorizontal) {
743 if (minSize.width > aMinSize) aMinSize = minSize.width;
745 if (maxSize.width < aMaxSize) aMaxSize = maxSize.width;
747 } else {
748 if (minSize.height > aMinSize) aMinSize = minSize.height;
750 if (maxSize.height < aMaxSize) aMaxSize = maxSize.height;
753 currentBox->collapsed = collapsed;
754 aFlexes += currentBox->flex;
756 last = currentBox;
757 currentBox = currentBox->next;
760 if (childCount > 0) {
761 nscoord maxAllowedFlex = nscoord_MAX / childCount;
763 if (MOZ_UNLIKELY(maxFlex > maxAllowedFlex)) {
764 // clamp all the flexes
765 currentBox = aBoxSizes;
766 while (currentBox) {
767 currentBox->flex = std::min(currentBox->flex, maxAllowedFlex);
768 currentBox = currentBox->next;
772 #ifdef DEBUG
773 else {
774 NS_ASSERTION(maxFlex == 0, "How did that happen?");
776 #endif
778 // we specified all our children are equal size;
779 if (frameState & NS_STATE_EQUAL_SIZE) {
780 smallestMaxWidth = std::max(smallestMaxWidth, biggestMinWidth);
781 biggestPrefWidth = nsIFrame::XULBoundsCheck(
782 biggestMinWidth, biggestPrefWidth, smallestMaxWidth);
784 currentBox = aBoxSizes;
786 while (currentBox) {
787 if (!currentBox->collapsed) {
788 currentBox->pref = biggestPrefWidth;
789 currentBox->min = biggestMinWidth;
790 currentBox->max = smallestMaxWidth;
791 } else {
792 currentBox->pref = 0;
793 currentBox->min = 0;
794 currentBox->max = 0;
796 currentBox = currentBox->next;
801 void nsSprocketLayout::ComputeChildsNextPosition(
802 nsIFrame* aBox, const nscoord& aCurX, const nscoord& aCurY, nscoord& aNextX,
803 nscoord& aNextY, const nsRect& aCurrentChildSize) {
804 // Get the position along the box axis for the child.
805 // The out-of-axis position is not set.
806 nsFrameState frameState = nsFrameState(0);
807 GetFrameState(aBox, frameState);
809 if (IsXULHorizontal(aBox)) {
810 // horizontal box's children.
811 if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
812 aNextX = aCurX + aCurrentChildSize.width;
813 else
814 aNextX = aCurX - aCurrentChildSize.width;
816 } else {
817 // vertical box's children.
818 if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
819 aNextY = aCurY + aCurrentChildSize.height;
820 else
821 aNextY = aCurY - aCurrentChildSize.height;
825 void nsSprocketLayout::AlignChildren(nsIFrame* aBox, nsBoxLayoutState& aState) {
826 nsFrameState frameState = nsFrameState(0);
827 GetFrameState(aBox, frameState);
828 bool isHorizontal = (frameState & NS_STATE_IS_HORIZONTAL) != 0;
829 nsRect clientRect;
830 aBox->GetXULClientRect(clientRect);
832 MOZ_ASSERT(!(frameState & NS_STATE_AUTO_STRETCH),
833 "Only AlignChildren() with non-stretch alignment");
835 // These are only calculated if needed
836 nsIFrame::Halignment halign;
837 nsIFrame::Valignment valign;
838 nscoord maxAscent = 0;
839 bool isLTR;
841 if (isHorizontal) {
842 valign = aBox->GetXULVAlign();
843 if (valign == nsBoxFrame::vAlign_BaseLine) {
844 maxAscent = aBox->GetXULBoxAscent(aState);
846 } else {
847 isLTR = GetFrameDirection(aBox) == StyleDirection::Ltr;
848 halign = aBox->GetXULHAlign();
851 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
852 nsIFrame* child = iter->get();
853 nsMargin margin;
854 child->GetXULMargin(margin);
855 nsRect childRect = child->GetRect();
857 if (isHorizontal) {
858 const nscoord startAlign = clientRect.y + margin.top;
859 const nscoord endAlign =
860 clientRect.YMost() - margin.bottom - childRect.height;
862 nscoord y = 0;
863 switch (valign) {
864 case nsBoxFrame::vAlign_Top:
865 y = startAlign;
866 break;
867 case nsBoxFrame::vAlign_Middle:
868 // Should this center the border box?
869 // This centers the margin box, the historical behavior.
870 y = (startAlign + endAlign) / 2;
871 break;
872 case nsBoxFrame::vAlign_Bottom:
873 y = endAlign;
874 break;
875 case nsBoxFrame::vAlign_BaseLine:
876 // Alignments don't force the box to grow (only sizes do),
877 // so keep the children within the box.
878 y = maxAscent - child->GetXULBoxAscent(aState);
879 y = std::max(startAlign, y);
880 y = std::min(y, endAlign);
881 break;
884 childRect.y = y;
886 } else { // vertical box
887 const nscoord leftAlign = clientRect.x + margin.left;
888 const nscoord rightAlign =
889 clientRect.XMost() - margin.right - childRect.width;
891 nscoord x = 0;
892 switch (halign) {
893 case nsBoxFrame::hAlign_Left: // start
894 x = isLTR ? leftAlign : rightAlign;
895 break;
896 case nsBoxFrame::hAlign_Center:
897 x = (leftAlign + rightAlign) / 2;
898 break;
899 case nsBoxFrame::hAlign_Right: // end
900 x = isLTR ? rightAlign : leftAlign;
901 break;
904 childRect.x = x;
907 if (childRect.TopLeft() != child->GetPosition()) {
908 child->SetXULBounds(aState, childRect);
913 void nsSprocketLayout::ChildResized(
914 nsIFrame* aBox, nsBoxLayoutState& aState, nsIFrame* aChild,
915 nsBoxSize* aChildBoxSize, nsComputedBoxSize* aChildComputedSize,
916 nsBoxSize* aBoxSizes, nsComputedBoxSize* aComputedBoxSizes,
917 const nsRect& aChildLayoutRect, nsRect& aChildActualRect,
918 nsRect& aContainingRect, int32_t aFlexes, bool& aFinished)
921 nsRect childCurrentRect(aChildLayoutRect);
923 bool isHorizontal = IsXULHorizontal(aBox);
924 nscoord childLayoutWidth = GET_WIDTH(aChildLayoutRect, isHorizontal);
925 nscoord& childActualWidth = GET_WIDTH(aChildActualRect, isHorizontal);
926 nscoord& containingWidth = GET_WIDTH(aContainingRect, isHorizontal);
928 // nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal);
929 nscoord& childActualHeight = GET_HEIGHT(aChildActualRect, isHorizontal);
930 nscoord& containingHeight = GET_HEIGHT(aContainingRect, isHorizontal);
932 bool recompute = false;
934 // if we are a horizontal box see if the child will fit inside us.
935 if (childActualHeight > containingHeight) {
936 // if we are a horizontal box and the child is bigger than our height
938 // ok if the height changed then we need to reflow everyone but us at the
939 // new height so we will set the changed index to be us. And signal that we
940 // need a new pass.
942 nsSize min = aChild->GetXULMinSize(aState);
943 nsSize max =
944 nsIFrame::XULBoundsCheckMinMax(min, aChild->GetXULMaxSize(aState));
945 AddXULMargin(aChild, max);
947 if (isHorizontal)
948 childActualHeight =
949 max.height < childActualHeight ? max.height : childActualHeight;
950 else
951 childActualHeight =
952 max.width < childActualHeight ? max.width : childActualHeight;
954 // only set if it changes
955 if (childActualHeight > containingHeight) {
956 containingHeight = childActualHeight;
958 // remember we do not need to clear the resized list because changing the
959 // height of a horizontal box will not affect the width of any of its
960 // children because block flow left to right, top to bottom. Just trust me
961 // on this one.
962 aFinished = false;
964 // only recompute if there are flexes.
965 if (aFlexes > 0) {
966 // relayout everything
967 recompute = true;
968 InvalidateComputedSizes(aComputedBoxSizes);
969 nsComputedBoxSize* node = aComputedBoxSizes;
971 while (node) {
972 node->resized = false;
973 node = node->next;
979 if (childActualWidth > childLayoutWidth) {
980 nsSize min = aChild->GetXULMinSize(aState);
981 nsSize max =
982 nsIFrame::XULBoundsCheckMinMax(min, aChild->GetXULMaxSize(aState));
984 AddXULMargin(aChild, max);
986 // our width now becomes the new size
988 if (isHorizontal)
989 childActualWidth =
990 max.width < childActualWidth ? max.width : childActualWidth;
991 else
992 childActualWidth =
993 max.height < childActualWidth ? max.height : childActualWidth;
995 if (childActualWidth > childLayoutWidth) {
996 aChildComputedSize->size = childActualWidth;
997 aChildBoxSize->min = childActualWidth;
998 if (aChildBoxSize->pref < childActualWidth)
999 aChildBoxSize->pref = childActualWidth;
1000 if (aChildBoxSize->max < childActualWidth)
1001 aChildBoxSize->max = childActualWidth;
1003 // if we have flexible elements with us then reflex things. Otherwise we
1004 // can skip doing it.
1005 if (aFlexes > 0) {
1006 InvalidateComputedSizes(aComputedBoxSizes);
1008 nsComputedBoxSize* node = aComputedBoxSizes;
1009 aChildComputedSize->resized = true;
1011 while (node) {
1012 if (node->resized) node->valid = true;
1014 node = node->next;
1017 recompute = true;
1018 aFinished = false;
1019 } else {
1020 containingWidth += aChildComputedSize->size - childLayoutWidth;
1025 if (recompute)
1026 ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes,
1027 aComputedBoxSizes);
1029 if (!childCurrentRect.IsEqualInterior(aChildActualRect)) {
1030 // the childRect includes the margin
1031 // make sure we remove it before setting
1032 // the bounds.
1033 nsMargin margin(0, 0, 0, 0);
1034 aChild->GetXULMargin(margin);
1035 nsRect rect(aChildActualRect);
1036 if (rect.width >= margin.left + margin.right &&
1037 rect.height >= margin.top + margin.bottom)
1038 rect.Deflate(margin);
1040 aChild->SetXULBounds(aState, rect);
1041 aChild->XULLayout(aState);
1045 void nsSprocketLayout::InvalidateComputedSizes(
1046 nsComputedBoxSize* aComputedBoxSizes) {
1047 while (aComputedBoxSizes) {
1048 aComputedBoxSizes->valid = false;
1049 aComputedBoxSizes = aComputedBoxSizes->next;
1053 void nsSprocketLayout::ComputeChildSizes(
1054 nsIFrame* aBox, nsBoxLayoutState& aState, nscoord& aGivenSize,
1055 nsBoxSize* aBoxSizes, nsComputedBoxSize*& aComputedBoxSizes) {
1056 // nscoord onePixel = aState.PresContext()->IntScaledPixelsToTwips(1);
1058 int32_t sizeRemaining = aGivenSize;
1059 int32_t spacerConstantsRemaining = 0;
1061 // ----- calculate the spacers constants and the size remaining -----
1063 if (!aComputedBoxSizes) aComputedBoxSizes = new (aState) nsComputedBoxSize();
1065 nsBoxSize* boxSizes = aBoxSizes;
1066 nsComputedBoxSize* computedBoxSizes = aComputedBoxSizes;
1067 int32_t count = 0;
1068 int32_t validCount = 0;
1070 while (boxSizes) {
1071 NS_ASSERTION(
1072 (boxSizes->min <= boxSizes->pref && boxSizes->pref <= boxSizes->max),
1073 "bad pref, min, max size");
1075 // ignore collapsed children
1076 // if (boxSizes->collapsed)
1077 // {
1078 // computedBoxSizes->valid = true;
1079 // computedBoxSizes->size = boxSizes->pref;
1080 // validCount++;
1081 // boxSizes->flex = 0;
1082 // }// else {
1084 if (computedBoxSizes->valid) {
1085 sizeRemaining -= computedBoxSizes->size;
1086 validCount++;
1087 } else {
1088 if (boxSizes->flex == 0) {
1089 computedBoxSizes->valid = true;
1090 computedBoxSizes->size = boxSizes->pref;
1091 validCount++;
1094 spacerConstantsRemaining += boxSizes->flex;
1095 sizeRemaining -= boxSizes->pref;
1098 sizeRemaining -= (boxSizes->left + boxSizes->right);
1102 boxSizes = boxSizes->next;
1104 if (boxSizes && !computedBoxSizes->next)
1105 computedBoxSizes->next = new (aState) nsComputedBoxSize();
1107 computedBoxSizes = computedBoxSizes->next;
1108 count++;
1111 // everything accounted for?
1112 if (validCount < count) {
1113 // ----- Ok we are give a size to fit into so stretch or squeeze to fit
1114 // ----- Make sure we look at our min and max size
1115 bool limit = true;
1116 for (int pass = 1; true == limit; pass++) {
1117 limit = false;
1118 boxSizes = aBoxSizes;
1119 computedBoxSizes = aComputedBoxSizes;
1121 while (boxSizes) {
1122 // ignore collapsed spacers
1124 // if (!boxSizes->collapsed) {
1126 nscoord pref = 0;
1127 nscoord max = NS_UNCONSTRAINEDSIZE;
1128 nscoord min = 0;
1129 nscoord flex = 0;
1131 pref = boxSizes->pref;
1132 min = boxSizes->min;
1133 max = boxSizes->max;
1134 flex = boxSizes->flex;
1136 // ----- look at our min and max limits make sure we aren't too small or
1137 // too big -----
1138 if (!computedBoxSizes->valid) {
1139 int32_t newSize = pref + int32_t(int64_t(sizeRemaining) * flex /
1140 spacerConstantsRemaining);
1142 if (newSize <= min) {
1143 computedBoxSizes->size = min;
1144 computedBoxSizes->valid = true;
1145 spacerConstantsRemaining -= flex;
1146 sizeRemaining += pref;
1147 sizeRemaining -= min;
1148 limit = true;
1149 } else if (newSize >= max) {
1150 computedBoxSizes->size = max;
1151 computedBoxSizes->valid = true;
1152 spacerConstantsRemaining -= flex;
1153 sizeRemaining += pref;
1154 sizeRemaining -= max;
1155 limit = true;
1158 // }
1159 boxSizes = boxSizes->next;
1160 computedBoxSizes = computedBoxSizes->next;
1165 // ---- once we have removed and min and max issues just stretch us out in the
1166 // remaining space
1167 // ---- or shrink us. Depends on the size remaining and the spacer constants
1168 aGivenSize = 0;
1169 boxSizes = aBoxSizes;
1170 computedBoxSizes = aComputedBoxSizes;
1172 while (boxSizes) {
1173 // ignore collapsed spacers
1174 // if (!(boxSizes && boxSizes->collapsed)) {
1176 nscoord pref = 0;
1177 nscoord flex = 0;
1178 pref = boxSizes->pref;
1179 flex = boxSizes->flex;
1181 if (!computedBoxSizes->valid) {
1182 computedBoxSizes->size = pref + int32_t(int64_t(sizeRemaining) * flex /
1183 spacerConstantsRemaining);
1184 computedBoxSizes->valid = true;
1187 aGivenSize += (boxSizes->left + boxSizes->right);
1188 aGivenSize += computedBoxSizes->size;
1190 // }
1192 boxSizes = boxSizes->next;
1193 computedBoxSizes = computedBoxSizes->next;
1197 nsSize nsSprocketLayout::GetXULPrefSize(nsIFrame* aBox,
1198 nsBoxLayoutState& aState) {
1199 nsSize vpref(0, 0);
1200 bool isHorizontal = IsXULHorizontal(aBox);
1202 nscoord biggestPref = 0;
1204 // run through all the children and get their min, max, and preferred sizes
1205 // return us the size of the box
1207 nsFrameState frameState = nsFrameState(0);
1208 GetFrameState(aBox, frameState);
1209 bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
1210 int32_t count = 0;
1212 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
1213 nsIFrame* child = iter->get();
1214 // ignore collapsed children
1215 if (child->IsXULCollapsed()) {
1216 continue;
1218 nsSize pref = child->GetXULPrefSize(aState);
1219 AddXULMargin(child, pref);
1221 if (isEqual) {
1222 if (isHorizontal) {
1223 if (pref.width > biggestPref) biggestPref = pref.width;
1224 } else {
1225 if (pref.height > biggestPref) biggestPref = pref.height;
1229 AddLargestSize(vpref, pref, isHorizontal);
1230 count++;
1233 if (isEqual) {
1234 if (isHorizontal)
1235 vpref.width = biggestPref * count;
1236 else
1237 vpref.height = biggestPref * count;
1240 // now add our border and padding
1241 AddXULBorderAndPadding(aBox, vpref);
1243 return vpref;
1246 nsSize nsSprocketLayout::GetXULMinSize(nsIFrame* aBox,
1247 nsBoxLayoutState& aState) {
1248 nsSize minSize(0, 0);
1249 bool isHorizontal = IsXULHorizontal(aBox);
1251 nscoord biggestMin = 0;
1253 // run through all the children and get their min, max, and preferred sizes
1254 // return us the size of the box
1256 nsFrameState frameState = nsFrameState(0);
1257 GetFrameState(aBox, frameState);
1258 bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
1259 int32_t count = 0;
1261 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
1262 nsIFrame* child = iter->get();
1264 // ignore collapsed children
1265 if (child->IsXULCollapsed()) {
1266 continue;
1269 nsSize min = child->GetXULMinSize(aState);
1270 nsSize pref(0, 0);
1272 // if the child is not flexible then
1273 // its min size is its pref size.
1274 if (child->GetXULFlex() == 0) {
1275 pref = child->GetXULPrefSize(aState);
1276 if (isHorizontal)
1277 min.width = pref.width;
1278 else
1279 min.height = pref.height;
1282 if (isEqual) {
1283 if (isHorizontal) {
1284 if (min.width > biggestMin) biggestMin = min.width;
1285 } else {
1286 if (min.height > biggestMin) biggestMin = min.height;
1290 AddXULMargin(child, min);
1291 AddLargestSize(minSize, min, isHorizontal);
1292 count++;
1295 if (isEqual) {
1296 if (isHorizontal)
1297 minSize.width = biggestMin * count;
1298 else
1299 minSize.height = biggestMin * count;
1302 // now add our border and padding
1303 AddXULBorderAndPadding(aBox, minSize);
1305 return minSize;
1308 nsSize nsSprocketLayout::GetXULMaxSize(nsIFrame* aBox,
1309 nsBoxLayoutState& aState) {
1310 bool isHorizontal = IsXULHorizontal(aBox);
1312 nscoord smallestMax = NS_UNCONSTRAINEDSIZE;
1313 nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
1315 // run through all the children and get their min, max, and preferred sizes
1316 // return us the size of the box
1318 nsFrameState frameState = nsFrameState(0);
1319 GetFrameState(aBox, frameState);
1320 bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE);
1321 int32_t count = 0;
1323 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
1324 nsIFrame* child = iter->get();
1326 // ignore collapsed children
1327 if (child->IsXULCollapsed()) {
1328 continue;
1330 // if completely redefined don't even ask our child for its size.
1331 nsSize min = child->GetXULMinSize(aState);
1332 nsSize max =
1333 nsIFrame::XULBoundsCheckMinMax(min, child->GetXULMaxSize(aState));
1335 AddXULMargin(child, max);
1336 AddSmallestSize(maxSize, max, isHorizontal);
1338 if (isEqual) {
1339 if (isHorizontal) {
1340 if (max.width < smallestMax) smallestMax = max.width;
1341 } else {
1342 if (max.height < smallestMax) smallestMax = max.height;
1345 count++;
1348 if (isEqual) {
1349 if (isHorizontal) {
1350 if (smallestMax != NS_UNCONSTRAINEDSIZE)
1351 maxSize.width = smallestMax * count;
1352 else
1353 maxSize.width = NS_UNCONSTRAINEDSIZE;
1354 } else {
1355 if (smallestMax != NS_UNCONSTRAINEDSIZE)
1356 maxSize.height = smallestMax * count;
1357 else
1358 maxSize.height = NS_UNCONSTRAINEDSIZE;
1362 // now add our border and padding
1363 AddXULBorderAndPadding(aBox, maxSize);
1365 return maxSize;
1368 nscoord nsSprocketLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState) {
1369 nscoord vAscent = 0;
1371 bool isHorizontal = IsXULHorizontal(aBox);
1373 // run through all the children and get their min, max, and preferred sizes
1374 // return us the size of the box
1376 for (auto iter = IterFor(aBox); iter && !iter->AtEnd(); iter->Next()) {
1377 nsIFrame* child = iter->get();
1379 // ignore collapsed children
1380 // if (!child->IsXULCollapsed())
1382 // if completely redefined don't even ask our child for its size.
1383 nscoord ascent = child->GetXULBoxAscent(aState);
1385 nsMargin margin;
1386 child->GetXULMargin(margin);
1387 ascent += margin.top;
1389 if (isHorizontal) {
1390 if (ascent > vAscent) vAscent = ascent;
1391 } else {
1392 if (vAscent == 0) vAscent = ascent;
1396 child = nsIFrame::GetNextXULBox(child);
1399 nsMargin borderPadding;
1400 aBox->GetXULBorderAndPadding(borderPadding);
1402 return vAscent + borderPadding.top;
1405 void nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2,
1406 bool aIsHorizontal) {
1407 if (aIsHorizontal) {
1408 if (aSize1.height < aSize2.height) aSize1.height = aSize2.height;
1409 } else {
1410 if (aSize1.width < aSize2.width) aSize1.width = aSize2.width;
1414 void nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2,
1415 bool aIsHorizontal) {
1416 if (aIsHorizontal) {
1417 if (aSize1.height > aSize2.height) aSize1.height = aSize2.height;
1418 } else {
1419 if (aSize1.width > aSize2.width) aSize1.width = aSize2.width;
1423 void nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd,
1424 bool aIsHorizontal) {
1425 if (aIsHorizontal)
1426 AddCoord(aSize.width, aSizeToAdd.width);
1427 else
1428 AddCoord(aSize.height, aSizeToAdd.height);
1430 SetLargestSize(aSize, aSizeToAdd, aIsHorizontal);
1433 void nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd) {
1434 if (aCoord != NS_UNCONSTRAINEDSIZE) {
1435 if (aCoordToAdd == NS_UNCONSTRAINEDSIZE)
1436 aCoord = aCoordToAdd;
1437 else
1438 aCoord += aCoordToAdd;
1441 void nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd,
1442 bool aIsHorizontal) {
1443 if (aIsHorizontal)
1444 AddCoord(aSize.width, aSizeToAdd.width);
1445 else
1446 AddCoord(aSize.height, aSizeToAdd.height);
1448 SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal);
1451 bool nsSprocketLayout::GetDefaultFlex(int32_t& aFlex) {
1452 aFlex = 0;
1453 return true;
1456 nsComputedBoxSize::nsComputedBoxSize() {
1457 resized = false;
1458 valid = false;
1459 size = 0;
1460 next = nullptr;
1463 nsBoxSize::nsBoxSize() {
1464 pref = 0;
1465 min = 0;
1466 max = NS_UNCONSTRAINEDSIZE;
1467 collapsed = false;
1468 left = 0;
1469 right = 0;
1470 flex = 0;
1471 next = nullptr;
1472 bogus = false;
1475 void* nsBoxSize::operator new(size_t sz,
1476 nsBoxLayoutState& aState) noexcept(true) {
1477 return mozilla::AutoStackArena::Allocate(sz);
1480 void nsBoxSize::operator delete(void* aPtr, size_t sz) {}
1482 void* nsComputedBoxSize::operator new(size_t sz,
1483 nsBoxLayoutState& aState) noexcept(true) {
1484 return mozilla::AutoStackArena::Allocate(sz);
1487 void nsComputedBoxSize::operator delete(void* aPtr, size_t sz) {}