void nsBox::AddMargin(nsIBox* aChild, nsSize& aSize) { nsMargin margin(0,0,0,0); aChild->GetMargin(margin); AddMargin(aSize, margin); }
void nsBox::AddBorderAndPadding(nsIBox* aBox, nsSize& aSize) { nsMargin borderPadding(0,0,0,0); aBox->GetBorderAndPadding(borderPadding); AddMargin(aSize, borderPadding); }
nsSize nsSprocketLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) { nsSize vpref (0, 0); bool isHorizontal = IsHorizontal(aBox); nscoord biggestPref = 0; // run through all the children and get their min, max, and preferred sizes // return us the size of the box nsIFrame* child = nsBox::GetChildBox(aBox); nsFrameState frameState = nsFrameState(0); GetFrameState(aBox, frameState); bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE); int32_t count = 0; while (child) { // ignore collapsed children if (!child->IsCollapsed()) { nsSize pref = child->GetPrefSize(aState); AddMargin(child, pref); if (isEqual) { if (isHorizontal) { if (pref.width > biggestPref) biggestPref = pref.width; } else { if (pref.height > biggestPref) biggestPref = pref.height; } } AddLargestSize(vpref, pref, isHorizontal); count++; } child = nsBox::GetNextBox(child); } if (isEqual) { if (isHorizontal) vpref.width = biggestPref*count; else vpref.height = biggestPref*count; } // now add our border and padding AddBorderAndPadding(aBox, vpref); return vpref; }
nsSize nsGridLayout2::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState) { nsSize maxSize = nsStackLayout::GetMaxSize(aBox, aState); // if there are no <rows> tags that will sum up our columns, // sum up our columns here. nsSize total(NS_INTRINSICSIZE, NS_INTRINSICSIZE); nsIBox* rowsBox = mGrid.GetRowsBox(); nsIBox* columnsBox = mGrid.GetColumnsBox(); if (!rowsBox || !columnsBox) { if (!rowsBox) { total.height = 0; // max height is the sum of our rows PRInt32 rows = mGrid.GetRowCount(); for (PRInt32 i=0; i < rows; i++) { nscoord height = mGrid.GetMaxRowHeight(aState, i, PR_TRUE); AddWidth(total, height, PR_FALSE); // AddHeight } } if (!columnsBox) { total.width = 0; // max height is the sum of our rows PRInt32 columns = mGrid.GetColumnCount(); for (PRInt32 i=0; i < columns; i++) { nscoord width = mGrid.GetMaxRowHeight(aState, i, PR_FALSE); AddWidth(total, width, PR_TRUE); // AddWidth } } AddMargin(aBox, total); AddOffset(aState, aBox, total); AddSmallestSize(maxSize, total); } return maxSize; }
nsSize nsStackLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState) { nsSize minSize (0, 0); // run through all the children and get their min, max, and preferred sizes nsIBox* child = aBox->GetChildBox(); while (child) { nsSize min = child->GetMinSize(aState); AddMargin(child, min); AddOffset(aState, child, min); AddLargestSize(minSize, min); child = child->GetNextBox(); } // now add our border and padding AddBorderAndPadding(aBox, minSize); return minSize; }
nsSize nsGridLayout2::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState) { nsSize pref = nsStackLayout::GetPrefSize(aBox, aState); // if there are no <rows> tags that will sum up our columns, // sum up our columns here. nsSize total(0,0); nsIBox* rowsBox = mGrid.GetRowsBox(); nsIBox* columnsBox = mGrid.GetColumnsBox(); if (!rowsBox || !columnsBox) { if (!rowsBox) { // max height is the sum of our rows PRInt32 rows = mGrid.GetRowCount(); for (PRInt32 i=0; i < rows; i++) { nscoord height = mGrid.GetPrefRowHeight(aState, i, PR_TRUE); AddWidth(total, height, PR_FALSE); // AddHeight } } if (!columnsBox) { // max height is the sum of our rows PRInt32 columns = mGrid.GetColumnCount(); for (PRInt32 i=0; i < columns; i++) { nscoord width = mGrid.GetPrefRowHeight(aState, i, PR_FALSE); AddWidth(total, width, PR_TRUE); // AddWidth } } AddMargin(aBox, total); AddOffset(aState, aBox, total); AddLargestSize(pref, total); } return pref; }
nsSize nsGridLayout2::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) { nsSize minSize = nsStackLayout::GetXULMinSize(aBox, aState); // if there are no <rows> tags that will sum up our columns, // sum up our columns here. nsSize total(0,0); nsIFrame* rowsBox = mGrid.GetRowsBox(); nsIFrame* columnsBox = mGrid.GetColumnsBox(); if (!rowsBox || !columnsBox) { if (!rowsBox) { // max height is the sum of our rows int32_t rows = mGrid.GetRowCount(); for (int32_t i=0; i < rows; i++) { nscoord height = mGrid.GetMinRowHeight(aState, i, true); AddWidth(total, height, false); // AddHeight } } if (!columnsBox) { // max height is the sum of our rows int32_t columns = mGrid.GetColumnCount(); for (int32_t i=0; i < columns; i++) { nscoord width = mGrid.GetMinRowHeight(aState, i, false); AddWidth(total, width, true); // AddWidth } } AddMargin(aBox, total); AddOffset(aBox, total); AddLargestSize(minSize, total); } return minSize; }
nsSize nsStackLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState) { nsSize rpref (0, 0); // we are as wide as the widest child plus its left offset // we are tall as the tallest child plus its top offset nsIBox* child = aBox->GetChildBox(); while (child) { nsSize pref = child->GetPrefSize(aState); AddMargin(child, pref); AddOffset(aState, child, pref); AddLargestSize(rpref, pref); child = child->GetNextBox(); } // now add our border and padding AddBorderAndPadding(aBox, rpref); return rpref; }
nsSize nsStackLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState) { nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE); // run through all the children and get their min, max, and preferred sizes nsIBox* child = aBox->GetChildBox(); while (child) { nsSize min = child->GetMinSize(aState); nsSize max = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState)); AddMargin(child, max); AddOffset(aState, child, max); AddSmallestSize(maxSize, max); child = child->GetNextBox(); } // now add our border and padding AddBorderAndPadding(aBox, maxSize); return maxSize; }
void nsBox::AddMargin(nsSize& aSize) { AddMargin(this, aSize); }
void nsSprocketLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes) { // used for the equal size flag nscoord biggestPrefWidth = 0; nscoord biggestMinWidth = 0; nscoord smallestMaxWidth = NS_INTRINSICSIZE; nsFrameState frameState = nsFrameState(0); GetFrameState(aBox, frameState); //if (frameState & NS_STATE_CURRENTLY_IN_DEBUG) // printf("In debug\n"); aMinSize = 0; aMaxSize = NS_INTRINSICSIZE; bool isHorizontal; if (IsHorizontal(aBox)) isHorizontal = true; else isHorizontal = false; // this is a nice little optimization // it turns out that if we only have 1 flexable child // then it does not matter what its preferred size is // there is nothing to flex it relative. This is great // because we can avoid asking for a preferred size in this // case. Why is this good? Well you might have html inside it // and asking html for its preferred size is rather expensive. // so we can just optimize it out this way. // set flexes nsIFrame* child = nsBox::GetChildBox(aBox); aFlexes = 0; nsBoxSize* currentBox = nullptr; #if 0 nsBoxSize* start = aBoxSizes; while(child) { // ok if we started with a list move down the list // until we reach the end. Then start looking at childen. // This feature is used extensively for Grid. nscoord flex = 0; if (!start) { if (!currentBox) { aBoxSizes = new (aState) nsBoxSize(); currentBox = aBoxSizes; } else { currentBox->next = new (aState) nsBoxSize(); currentBox = currentBox->next; } flex = child->GetFlex(aState); currentBox->flex = flex; currentBox->collapsed = child->IsCollapsed(); } else { flex = start->flex; start = start->next; } if (flex > 0) aFlexes++; child = GetNextBox(child); } #endif // get pref, min, max child = nsBox::GetChildBox(aBox); currentBox = aBoxSizes; nsBoxSize* last = nullptr; nscoord maxFlex = 0; int32_t childCount = 0; while(child) { while (currentBox && currentBox->bogus) { last = currentBox; currentBox = currentBox->next; } ++childCount; nsSize pref(0,0); nsSize minSize(0,0); nsSize maxSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE); nscoord ascent = 0; bool collapsed = child->IsCollapsed(); if (!collapsed) { // only one flexible child? Cool we will just make its preferred size // 0 then and not even have to ask for it. //if (flexes != 1) { pref = child->GetPrefSize(aState); minSize = child->GetMinSize(aState); maxSize = nsBox::BoundsCheckMinMax(minSize, child->GetMaxSize(aState)); ascent = child->GetBoxAscent(aState); nsMargin margin; child->GetMargin(margin); ascent += margin.top; //} pref = nsBox::BoundsCheck(minSize, pref, maxSize); AddMargin(child, pref); AddMargin(child, minSize); AddMargin(child, maxSize); } if (!currentBox) { // create one. currentBox = new (aState) nsBoxSize(); if (!aBoxSizes) { aBoxSizes = currentBox; last = aBoxSizes; } else { last->next = currentBox; last = currentBox; } nscoord minWidth; nscoord maxWidth; nscoord prefWidth; // get sizes from child if (isHorizontal) { minWidth = minSize.width; maxWidth = maxSize.width; prefWidth = pref.width; } else { minWidth = minSize.height; maxWidth = maxSize.height; prefWidth = pref.height; } nscoord flex = child->GetFlex(aState); // set them if you collapsed you are not flexible. if (collapsed) { currentBox->flex = 0; } else { if (flex > maxFlex) { maxFlex = flex; } currentBox->flex = flex; } // we specified all our children are equal size; if (frameState & NS_STATE_EQUAL_SIZE) { if (prefWidth > biggestPrefWidth) biggestPrefWidth = prefWidth; if (minWidth > biggestMinWidth) biggestMinWidth = minWidth; if (maxWidth < smallestMaxWidth) smallestMaxWidth = maxWidth; } else { // not we can set our children right now. currentBox->pref = prefWidth; currentBox->min = minWidth; currentBox->max = maxWidth; } NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,"Bad min, pref, max widths!"); } if (!isHorizontal) { if (minSize.width > aMinSize) aMinSize = minSize.width; if (maxSize.width < aMaxSize) aMaxSize = maxSize.width; } else { if (minSize.height > aMinSize) aMinSize = minSize.height; if (maxSize.height < aMaxSize) aMaxSize = maxSize.height; } currentBox->collapsed = collapsed; aFlexes += currentBox->flex; child = nsBox::GetNextBox(child); last = currentBox; currentBox = currentBox->next; } if (childCount > 0) { nscoord maxAllowedFlex = nscoord_MAX / childCount; if (MOZ_UNLIKELY(maxFlex > maxAllowedFlex)) { // clamp all the flexes currentBox = aBoxSizes; while (currentBox) { currentBox->flex = std::min(currentBox->flex, maxAllowedFlex); currentBox = currentBox->next; } } } #ifdef DEBUG else { NS_ASSERTION(maxFlex == 0, "How did that happen?"); } #endif // we specified all our children are equal size; if (frameState & NS_STATE_EQUAL_SIZE) { smallestMaxWidth = std::max(smallestMaxWidth, biggestMinWidth); biggestPrefWidth = nsBox::BoundsCheck(biggestMinWidth, biggestPrefWidth, smallestMaxWidth); currentBox = aBoxSizes; while(currentBox) { if (!currentBox->collapsed) { currentBox->pref = biggestPrefWidth; currentBox->min = biggestMinWidth; currentBox->max = smallestMaxWidth; } else { currentBox->pref = 0; currentBox->min = 0; currentBox->max = 0; } currentBox = currentBox->next; } } }
NS_IMETHODIMP nsSprocketLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aState) { // See if we are collapsed. If we are, then simply iterate over all our // children and give them a rect of 0 width and height. if (aBox->IsCollapsed()) { nsIFrame* child = nsBox::GetChildBox(aBox); while(child) { nsBoxFrame::LayoutChildAt(aState, child, nsRect(0,0,0,0)); child = nsBox::GetNextBox(child); } return NS_OK; } nsBoxLayoutState::AutoReflowDepth depth(aState); mozilla::AutoStackArena arena; // ----- figure out our size ---------- const nsSize originalSize = aBox->GetSize(); // -- make sure we remove our border and padding ---- nsRect clientRect; aBox->GetClientRect(clientRect); // |originalClientRect| represents the rect of the entire box (excluding borders // and padding). We store it here because we're going to use |clientRect| to hold // the required size for all our kids. As an example, consider an hbox with a // specified width of 300. If the kids total only 150 pixels of width, then // we have 150 pixels left over. |clientRect| is going to hold a width of 150 and // is going to be adjusted based off the value of the PACK property. If flexible // objects are in the box, then the two rects will match. nsRect originalClientRect(clientRect); // The frame state contains cached knowledge about our box, such as our orientation // and direction. nsFrameState frameState = nsFrameState(0); GetFrameState(aBox, frameState); // Build a list of our children's desired sizes and computed sizes nsBoxSize* boxSizes = nullptr; nsComputedBoxSize* computedBoxSizes = nullptr; nscoord min = 0; nscoord max = 0; int32_t flexes = 0; PopulateBoxSizes(aBox, aState, boxSizes, min, max, flexes); // The |size| variable will hold the total size of children along the axis of // the box. Continuing with the example begun in the comment above, size would // be 150 pixels. nscoord size = clientRect.width; if (!IsHorizontal(aBox)) size = clientRect.height; ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes); // After the call to ComputeChildSizes, the |size| variable contains the // total required size of all the children. We adjust our clientRect in the // appropriate dimension to match this size. In our example, we now assign // 150 pixels into the clientRect.width. // // The variables |min| and |max| hold the minimum required size box must be // in the OPPOSITE orientation, e.g., for a horizontal box, |min| is the minimum // height we require to enclose our children, and |max| is the maximum height // required to enclose our children. if (IsHorizontal(aBox)) { clientRect.width = size; if (clientRect.height < min) clientRect.height = min; if (frameState & NS_STATE_AUTO_STRETCH) { if (clientRect.height > max) clientRect.height = max; } } else { clientRect.height = size; if (clientRect.width < min) clientRect.width = min; if (frameState & NS_STATE_AUTO_STRETCH) { if (clientRect.width > max) clientRect.width = max; } } // With the sizes computed, now it's time to lay out our children. bool finished; nscoord passes = 0; // We flow children at their preferred locations (along with the appropriate computed flex). // After we flow a child, it is possible that the child will change its size. If/when this happens, // we have to do another pass. Typically only 2 passes are required, but the code is prepared to // do as many passes as are necessary to achieve equilibrium. nscoord x = 0; nscoord y = 0; nscoord origX = 0; nscoord origY = 0; // |childResized| lets us know if a child changed its size after we attempted to lay it out at // the specified size. If this happens, we usually have to do another pass. bool childResized = false; // |passes| stores our number of passes. If for any reason we end up doing more than, say, 10 // passes, we assert to indicate that something is seriously screwed up. passes = 0; do { #ifdef DEBUG_REFLOW if (passes > 0) { AddIndents(); printf("ChildResized doing pass: %d\n", passes); } #endif // Always assume that we're done. This will change if, for example, children don't stay // the same size after being flowed. finished = true; // Handle box packing. HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect); // Now that packing is taken care of we set up a few additional // tracking variables. origX = x; origY = y; // Now we iterate over our box children and our box size lists in // parallel. For each child, we look at its sizes and figure out // where to place it. nsComputedBoxSize* childComputedBoxSize = computedBoxSizes; nsBoxSize* childBoxSize = boxSizes; nsIFrame* child = nsBox::GetChildBox(aBox); int32_t count = 0; while (child || (childBoxSize && childBoxSize->bogus)) { // If for some reason, our lists are not the same length, we guard // by bailing out of the loop. if (childBoxSize == nullptr) { NS_NOTREACHED("Lists not the same length."); break; } nscoord width = clientRect.width; nscoord height = clientRect.height; if (!childBoxSize->bogus) { // We have a valid box size entry. This entry already contains information about our // sizes along the axis of the box (e.g., widths in a horizontal box). If our default // ALIGN is not stretch, however, then we also need to know the child's size along the // opposite axis. if (!(frameState & NS_STATE_AUTO_STRETCH)) { nsSize prefSize = child->GetPrefSize(aState); nsSize minSize = child->GetMinSize(aState); nsSize maxSize = child->GetMaxSize(aState); prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize); AddMargin(child, prefSize); width = std::min(prefSize.width, originalClientRect.width); height = std::min(prefSize.height, originalClientRect.height); } } // Obtain the computed size along the axis of the box for this child from the computedBoxSize entry. // We store the result in |width| for horizontal boxes and |height| for vertical boxes. if (frameState & NS_STATE_IS_HORIZONTAL) width = childComputedBoxSize->size; else height = childComputedBoxSize->size; // Adjust our x/y for the left/right spacing. if (frameState & NS_STATE_IS_HORIZONTAL) { if (frameState & NS_STATE_IS_DIRECTION_NORMAL) x += (childBoxSize->left); else x -= (childBoxSize->right); } else { if (frameState & NS_STATE_IS_DIRECTION_NORMAL) y += (childBoxSize->left); else y -= (childBoxSize->right); } // Now we build a child rect. nscoord rectX = x; nscoord rectY = y; if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) { if (frameState & NS_STATE_IS_HORIZONTAL) rectX -= width; else rectY -= height; } // We now create an accurate child rect based off our computed size information. nsRect childRect(rectX, rectY, width, height); // Sanity check against our clientRect. It is possible that a child specified // a size that is too large to fit. If that happens, then we have to grow // our client rect. Remember, clientRect is not the total rect of the enclosing // box. It currently holds our perception of how big the children needed to // be. if (childRect.width > clientRect.width) clientRect.width = childRect.width; if (childRect.height > clientRect.height) clientRect.height = childRect.height; // Either |nextX| or |nextY| is updated by this function call, according // to our axis. nscoord nextX = x; nscoord nextY = y; ComputeChildsNextPosition(aBox, x, y, nextX, nextY, childRect); // Now we further update our nextX/Y along our axis. // We also set childRect.y/x along the opposite axis appropriately for a // stretch alignment. (Non-stretch alignment is handled below.) if (frameState & NS_STATE_IS_HORIZONTAL) { if (frameState & NS_STATE_IS_DIRECTION_NORMAL) nextX += (childBoxSize->right); else nextX -= (childBoxSize->left); childRect.y = originalClientRect.y; } else { if (frameState & NS_STATE_IS_DIRECTION_NORMAL) nextY += (childBoxSize->right); else nextY -= (childBoxSize->left); childRect.x = originalClientRect.x; } // If we encounter a completely bogus box size, we just leave this child completely // alone and continue through the loop to the next child. if (childBoxSize->bogus) { childComputedBoxSize = childComputedBoxSize->next; childBoxSize = childBoxSize->next; count++; x = nextX; y = nextY; continue; } nsMargin margin(0,0,0,0); bool layout = true; // Deflate the rect of our child by its margin. child->GetMargin(margin); childRect.Deflate(margin); if (childRect.width < 0) childRect.width = 0; if (childRect.height < 0) childRect.height = 0; // Now we're trying to figure out if we have to lay out this child, i.e., to call // the child's Layout method. if (passes > 0) { layout = false; } else { // Always perform layout if we are dirty or have dirty children if (!NS_SUBTREE_DIRTY(child)) layout = false; } nsRect oldRect(child->GetRect()); // Non-stretch alignment will be handled in AlignChildren(), so don't // change child out-of-axis positions yet. if (!(frameState & NS_STATE_AUTO_STRETCH)) { if (frameState & NS_STATE_IS_HORIZONTAL) { childRect.y = oldRect.y; } else { childRect.x = oldRect.x; } } // We computed a childRect. Now we want to set the bounds of the child to be that rect. // If our old rect is different, then we know our size changed and we cache that fact // in the |sizeChanged| variable. child->SetBounds(aState, childRect); bool sizeChanged = (childRect.width != oldRect.width || childRect.height != oldRect.height); if (sizeChanged) { // Our size is different. Sanity check against our maximum allowed size to ensure // we didn't exceed it. nsSize minSize = child->GetMinSize(aState); nsSize maxSize = child->GetMaxSize(aState); maxSize = nsBox::BoundsCheckMinMax(minSize, maxSize); // make sure the size is in our max size. if (childRect.width > maxSize.width) childRect.width = maxSize.width; if (childRect.height > maxSize.height) childRect.height = maxSize.height; // set it again child->SetBounds(aState, childRect); } // If we already determined that layout was required or if our size has changed, then // we make sure to call layout on the child, since its children may need to be shifted // around as a result of the size change. if (layout || sizeChanged) child->Layout(aState); // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout. // We have to check for this. nsRect newChildRect(child->GetRect()); if (!newChildRect.IsEqualInterior(childRect)) { #ifdef DEBUG_GROW child->DumpBox(stdout); printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height); #endif newChildRect.Inflate(margin); childRect.Inflate(margin); // The child changed size during layout. The ChildResized method handles this // scenario. ChildResized(aBox, aState, child, childBoxSize, childComputedBoxSize, boxSizes, computedBoxSizes, childRect, newChildRect, clientRect, flexes, finished); // We note that a child changed size, which means that another pass will be required. childResized = true; // Now that a child resized, it's entirely possible that OUR rect is too small. Now we // ensure that |originalClientRect| is grown to accommodate the size of |clientRect|. if (clientRect.width > originalClientRect.width) originalClientRect.width = clientRect.width; if (clientRect.height > originalClientRect.height) originalClientRect.height = clientRect.height; if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) { // Our childRect had its XMost() or YMost() (depending on our layout // direction), positioned at a certain point. Ensure that the // newChildRect satisfies the same constraint. Note that this is // just equivalent to adjusting the x/y by the difference in // width/height between childRect and newChildRect. So we don't need // to reaccount for the left and right of the box layout state again. if (frameState & NS_STATE_IS_HORIZONTAL) newChildRect.x = childRect.XMost() - newChildRect.width; else newChildRect.y = childRect.YMost() - newChildRect.height; } // If the child resized then recompute its position. ComputeChildsNextPosition(aBox, x, y, nextX, nextY, newChildRect); if (newChildRect.width >= margin.left + margin.right && newChildRect.height >= margin.top + margin.bottom) newChildRect.Deflate(margin); if (childRect.width >= margin.left + margin.right && childRect.height >= margin.top + margin.bottom) childRect.Deflate(margin); child->SetBounds(aState, newChildRect); // If we are the first box that changed size, then we don't need to do a second pass if (count == 0) finished = true; } // Now update our x/y finally. x = nextX; y = nextY; // Move to the next child. childComputedBoxSize = childComputedBoxSize->next; childBoxSize = childBoxSize->next; child = nsBox::GetNextBox(child); count++; } // Sanity-checking code to ensure we don't do an infinite # of passes. passes++; NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!"); if (passes > 10) break; } while (false == finished); // Get rid of our size lists. while(boxSizes) { nsBoxSize* toDelete = boxSizes; boxSizes = boxSizes->next; delete toDelete; } while(computedBoxSizes) { nsComputedBoxSize* toDelete = computedBoxSizes; computedBoxSizes = computedBoxSizes->next; delete toDelete; } if (childResized) { // See if one of our children forced us to get bigger nsRect tmpClientRect(originalClientRect); nsMargin bp(0,0,0,0); aBox->GetBorderAndPadding(bp); tmpClientRect.Inflate(bp); if (tmpClientRect.width > originalSize.width || tmpClientRect.height > originalSize.height) { // if it did reset our bounds. nsRect bounds(aBox->GetRect()); if (tmpClientRect.width > originalSize.width) bounds.width = tmpClientRect.width; if (tmpClientRect.height > originalSize.height) bounds.height = tmpClientRect.height; aBox->SetBounds(aState, bounds); } } // Because our size grew, we now have to readjust because of box packing. Repack // in order to update our x and y to the correct values. HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect); // Compare against our original x and y and only worry about adjusting the children if // we really did have to change the positions because of packing (typically for 'center' // or 'end' pack values). if (x != origX || y != origY) { nsIFrame* child = nsBox::GetChildBox(aBox); // reposition all our children while (child) { nsRect childRect(child->GetRect()); childRect.x += (x - origX); childRect.y += (y - origY); child->SetBounds(aState, childRect); child = nsBox::GetNextBox(child); } } // Perform out-of-axis alignment for non-stretch alignments if (!(frameState & NS_STATE_AUTO_STRETCH)) { AlignChildren(aBox, aState); } // That's it! If you made it this far without having a nervous breakdown, // congratulations! Go get yourself a beer. return NS_OK; }
nsSize nsSprocketLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) { bool isHorizontal = IsHorizontal(aBox); nscoord smallestMax = NS_INTRINSICSIZE; nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE); // run through all the children and get their min, max, and preferred sizes // return us the size of the box nsIFrame* child = nsBox::GetChildBox(aBox); nsFrameState frameState = nsFrameState(0); GetFrameState(aBox, frameState); bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE); int32_t count = 0; while (child) { // ignore collapsed children if (!child->IsCollapsed()) { // if completely redefined don't even ask our child for its size. nsSize min = child->GetMinSize(aState); nsSize max = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState)); AddMargin(child, max); AddSmallestSize(maxSize, max, isHorizontal); if (isEqual) { if (isHorizontal) { if (max.width < smallestMax) smallestMax = max.width; } else { if (max.height < smallestMax) smallestMax = max.height; } } count++; } child = nsBox::GetNextBox(child); } if (isEqual) { if (isHorizontal) { if (smallestMax != NS_INTRINSICSIZE) maxSize.width = smallestMax*count; else maxSize.width = NS_INTRINSICSIZE; } else { if (smallestMax != NS_INTRINSICSIZE) maxSize.height = smallestMax*count; else maxSize.height = NS_INTRINSICSIZE; } } // now add our border and padding AddBorderAndPadding(aBox, maxSize); return maxSize; }
nsSize nsSprocketLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) { nsSize minSize (0, 0); bool isHorizontal = IsHorizontal(aBox); nscoord biggestMin = 0; // run through all the children and get their min, max, and preferred sizes // return us the size of the box nsIFrame* child = nsBox::GetChildBox(aBox); nsFrameState frameState = nsFrameState(0); GetFrameState(aBox, frameState); bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE); int32_t count = 0; while (child) { // ignore collapsed children if (!child->IsCollapsed()) { nsSize min = child->GetMinSize(aState); nsSize pref(0,0); // if the child is not flexible then // its min size is its pref size. if (child->GetFlex(aState) == 0) { pref = child->GetPrefSize(aState); if (isHorizontal) min.width = pref.width; else min.height = pref.height; } if (isEqual) { if (isHorizontal) { if (min.width > biggestMin) biggestMin = min.width; } else { if (min.height > biggestMin) biggestMin = min.height; } } AddMargin(child, min); AddLargestSize(minSize, min, isHorizontal); count++; } child = nsBox::GetNextBox(child); } if (isEqual) { if (isHorizontal) minSize.width = biggestMin*count; else minSize.height = biggestMin*count; } // now add our border and padding AddBorderAndPadding(aBox, minSize); return minSize; }
void nsSprocketLayout::ChildResized(nsIFrame* aBox, nsBoxLayoutState& aState, nsIFrame* aChild, nsBoxSize* aChildBoxSize, nsComputedBoxSize* aChildComputedSize, nsBoxSize* aBoxSizes, nsComputedBoxSize* aComputedBoxSizes, const nsRect& aChildLayoutRect, nsRect& aChildActualRect, nsRect& aContainingRect, int32_t aFlexes, bool& aFinished) { nsRect childCurrentRect(aChildLayoutRect); bool isHorizontal = IsHorizontal(aBox); nscoord childLayoutWidth = GET_WIDTH(aChildLayoutRect,isHorizontal); nscoord& childActualWidth = GET_WIDTH(aChildActualRect,isHorizontal); nscoord& containingWidth = GET_WIDTH(aContainingRect,isHorizontal); //nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal); nscoord& childActualHeight = GET_HEIGHT(aChildActualRect,isHorizontal); nscoord& containingHeight = GET_HEIGHT(aContainingRect,isHorizontal); bool recompute = false; // if we are a horizontal box see if the child will fit inside us. if ( childActualHeight > containingHeight) { // if we are a horizontal box and the child is bigger than our height // ok if the height changed then we need to reflow everyone but us at the new height // so we will set the changed index to be us. And signal that we need a new pass. nsSize min = aChild->GetMinSize(aState); nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetMaxSize(aState)); AddMargin(aChild, max); if (isHorizontal) childActualHeight = max.height < childActualHeight ? max.height : childActualHeight; else childActualHeight = max.width < childActualHeight ? max.width : childActualHeight; // only set if it changes if (childActualHeight > containingHeight) { containingHeight = childActualHeight; // remember we do not need to clear the resized list because changing the height of a horizontal box // will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me // on this one. aFinished = false; // only recompute if there are flexes. if (aFlexes > 0) { // relayout everything recompute = true; InvalidateComputedSizes(aComputedBoxSizes); nsComputedBoxSize* node = aComputedBoxSizes; while(node) { node->resized = false; node = node->next; } } } } if (childActualWidth > childLayoutWidth) { nsSize min = aChild->GetMinSize(aState); nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetMaxSize(aState)); AddMargin(aChild, max); // our width now becomes the new size if (isHorizontal) childActualWidth = max.width < childActualWidth ? max.width : childActualWidth; else childActualWidth = max.height < childActualWidth ? max.height : childActualWidth; if (childActualWidth > childLayoutWidth) { aChildComputedSize->size = childActualWidth; aChildBoxSize->min = childActualWidth; if (aChildBoxSize->pref < childActualWidth) aChildBoxSize->pref = childActualWidth; if (aChildBoxSize->max < childActualWidth) aChildBoxSize->max = childActualWidth; // if we have flexible elements with us then reflex things. Otherwise we can skip doing it. if (aFlexes > 0) { InvalidateComputedSizes(aComputedBoxSizes); nsComputedBoxSize* node = aComputedBoxSizes; aChildComputedSize->resized = true; while(node) { if (node->resized) node->valid = true; node = node->next; } recompute = true; aFinished = false; } else { containingWidth += aChildComputedSize->size - childLayoutWidth; } } } if (recompute) ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes, aComputedBoxSizes); if (!childCurrentRect.IsEqualInterior(aChildActualRect)) { // the childRect includes the margin // make sure we remove it before setting // the bounds. nsMargin margin(0,0,0,0); aChild->GetMargin(margin); nsRect rect(aChildActualRect); if (rect.width >= margin.left + margin.right && rect.height >= margin.top + margin.bottom) rect.Deflate(margin); aChild->SetBounds(aState, rect); aChild->Layout(aState); } }