diff options
Diffstat (limited to 'layout/xul/nsStackLayout.cpp')
-rw-r--r-- | layout/xul/nsStackLayout.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/layout/xul/nsStackLayout.cpp b/layout/xul/nsStackLayout.cpp new file mode 100644 index 0000000000..2a377a07f9 --- /dev/null +++ b/layout/xul/nsStackLayout.cpp @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// +// Eric Vaughan +// Netscape Communications +// +// See documentation in associated header file +// + +#include "nsStackLayout.h" +#include "nsCOMPtr.h" +#include "nsBoxLayoutState.h" +#include "nsBoxFrame.h" +#include "nsGkAtoms.h" +#include "nsIContent.h" +#include "nsNameSpaceManager.h" + +using namespace mozilla; + +nsBoxLayout* nsStackLayout::gInstance = nullptr; + +nsresult NS_NewStackLayout(nsCOMPtr<nsBoxLayout>& aNewLayout) { + if (!nsStackLayout::gInstance) { + nsStackLayout::gInstance = new nsStackLayout(); + NS_IF_ADDREF(nsStackLayout::gInstance); + } + // we have not instance variables so just return our static one. + aNewLayout = nsStackLayout::gInstance; + return NS_OK; +} + +/*static*/ +void nsStackLayout::Shutdown() { NS_IF_RELEASE(gInstance); } + +nsStackLayout::nsStackLayout() = default; + +/* + * Sizing: we are as wide as the widest child + * we are tall as the tallest child. + */ + +nsSize nsStackLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) { + nsSize prefSize(0, 0); + + nsIFrame* child = nsIFrame::GetChildXULBox(aBox); + while (child) { + nsSize pref = child->GetXULPrefSize(aState); + + AddXULMargin(child, pref); + + if (pref.width > prefSize.width) { + prefSize.width = pref.width; + } + if (pref.height > prefSize.height) { + prefSize.height = pref.height; + } + + child = nsIFrame::GetNextXULBox(child); + } + + AddXULBorderAndPadding(aBox, prefSize); + + return prefSize; +} + +nsSize nsStackLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) { + nsSize minSize(0, 0); + + nsIFrame* child = nsIFrame::GetChildXULBox(aBox); + while (child) { + nsSize min = child->GetXULMinSize(aState); + + AddXULMargin(child, min); + + if (min.width > minSize.width) { + minSize.width = min.width; + } + if (min.height > minSize.height) { + minSize.height = min.height; + } + + child = nsIFrame::GetNextXULBox(child); + } + + AddXULBorderAndPadding(aBox, minSize); + + return minSize; +} + +nsSize nsStackLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) { + nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); + + nsIFrame* child = nsIFrame::GetChildXULBox(aBox); + while (child) { + nsSize min = child->GetXULMinSize(aState); + nsSize max = child->GetXULMaxSize(aState); + + max = nsIFrame::XULBoundsCheckMinMax(min, max); + + AddXULMargin(child, max); + + if (max.width < maxSize.width) { + maxSize.width = max.width; + } + if (max.height < maxSize.height) { + maxSize.height = max.height; + } + + child = nsIFrame::GetNextXULBox(child); + } + + AddXULBorderAndPadding(aBox, maxSize); + + return maxSize; +} + +nscoord nsStackLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState) { + nscoord vAscent = 0; + + nsIFrame* child = nsIFrame::GetChildXULBox(aBox); + while (child) { + nscoord ascent = child->GetXULBoxAscent(aState); + nsMargin margin; + child->GetXULMargin(margin); + ascent += margin.top; + if (ascent > vAscent) vAscent = ascent; + + child = nsIFrame::GetNextXULBox(child); + } + + return vAscent; +} + +NS_IMETHODIMP +nsStackLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) { + nsRect clientRect; + aBox->GetXULClientRect(clientRect); + + bool grow; + + do { + nsIFrame* child = nsIFrame::GetChildXULBox(aBox); + grow = false; + + while (child) { + nsMargin margin; + child->GetXULMargin(margin); + nsRect childRect(clientRect); + childRect.Deflate(margin); + + if (childRect.width < 0) childRect.width = 0; + + if (childRect.height < 0) childRect.height = 0; + + nsRect oldRect(child->GetRect()); + bool sizeChanged = !oldRect.IsEqualEdges(childRect); + + // only lay out dirty children or children whose sizes have changed + if (sizeChanged || child->IsSubtreeDirty()) { + // add in the child's margin + nsMargin margin; + child->GetXULMargin(margin); + + // Now place the child. + child->SetXULBounds(aState, childRect); + + // Flow the child. + child->XULLayout(aState); + + // Get the child's new rect. + childRect = child->GetRect(); + childRect.Inflate(margin); + + // Did the child push back on us and get bigger? + if (childRect.width > clientRect.width) { + clientRect.width = childRect.width; + grow = true; + } + + if (childRect.height > clientRect.height) { + clientRect.height = childRect.height; + grow = true; + } + } + + child = nsIFrame::GetNextXULBox(child); + } + } while (grow); + + // if some HTML inside us got bigger we need to force ourselves to + // get bigger + nsRect bounds(aBox->GetRect()); + nsMargin bp; + aBox->GetXULBorderAndPadding(bp); + clientRect.Inflate(bp); + + if (clientRect.width > bounds.width || clientRect.height > bounds.height) { + if (clientRect.width > bounds.width) bounds.width = clientRect.width; + if (clientRect.height > bounds.height) bounds.height = clientRect.height; + + aBox->SetXULBounds(aState, bounds); + } + + return NS_OK; +} |