summaryrefslogtreecommitdiffstats
path: root/layout/xul/nsBox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/xul/nsBox.cpp')
-rw-r--r--layout/xul/nsBox.cpp981
1 files changed, 981 insertions, 0 deletions
diff --git a/layout/xul/nsBox.cpp b/layout/xul/nsBox.cpp
new file mode 100644
index 000000000..f7ec5fead
--- /dev/null
+++ b/layout/xul/nsBox.cpp
@@ -0,0 +1,981 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsBoxLayoutState.h"
+#include "nsBox.h"
+#include "nsBoxFrame.h"
+#include "nsPresContext.h"
+#include "nsCOMPtr.h"
+#include "nsIContent.h"
+#include "nsContainerFrame.h"
+#include "nsNameSpaceManager.h"
+#include "nsGkAtoms.h"
+#include "nsIDOMNode.h"
+#include "nsIDOMMozNamedAttrMap.h"
+#include "nsIDOMAttr.h"
+#include "nsITheme.h"
+#include "nsIServiceManager.h"
+#include "nsBoxLayout.h"
+#include "FrameLayerBuilder.h"
+#include <algorithm>
+
+using namespace mozilla;
+
+#ifdef DEBUG_LAYOUT
+int32_t gIndent = 0;
+#endif
+
+#ifdef DEBUG_LAYOUT
+void
+nsBoxAddIndents()
+{
+ for(int32_t i=0; i < gIndent; i++)
+ {
+ printf(" ");
+ }
+}
+#endif
+
+#ifdef DEBUG_LAYOUT
+void
+nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult)
+{
+ aResult.Append(aAttribute);
+ aResult.AppendLiteral("='");
+ aResult.Append(aValue);
+ aResult.AppendLiteral("' ");
+}
+
+void
+nsBox::ListBox(nsAutoString& aResult)
+{
+ nsAutoString name;
+ GetBoxName(name);
+
+ char addr[100];
+ sprintf(addr, "[@%p] ", static_cast<void*>(this));
+
+ aResult.AppendASCII(addr);
+ aResult.Append(name);
+ aResult.Append(' ');
+
+ nsIContent* content = GetContent();
+
+ // add on all the set attributes
+ if (content) {
+ nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
+ nsCOMPtr<nsIDOMMozNamedAttrMap> namedMap;
+
+ node->GetAttributes(getter_AddRefs(namedMap));
+ uint32_t length;
+ namedMap->GetLength(&length);
+
+ nsCOMPtr<nsIDOMAttr> attribute;
+ for (uint32_t i = 0; i < length; ++i)
+ {
+ namedMap->Item(i, getter_AddRefs(attribute));
+ attribute->GetName(name);
+ nsAutoString value;
+ attribute->GetValue(value);
+ AppendAttribute(name, value, aResult);
+ }
+ }
+}
+
+nsresult
+nsBox::XULDumpBox(FILE* aFile)
+{
+ nsAutoString s;
+ ListBox(s);
+ fprintf(aFile, "%s", NS_LossyConvertUTF16toASCII(s).get());
+ return NS_OK;
+}
+
+void
+nsBox::PropagateDebug(nsBoxLayoutState& aState)
+{
+ // propagate debug information
+ if (mState & NS_STATE_DEBUG_WAS_SET) {
+ if (mState & NS_STATE_SET_TO_DEBUG)
+ SetXULDebug(aState, true);
+ else
+ SetXULDebug(aState, false);
+ } else if (mState & NS_STATE_IS_ROOT) {
+ SetXULDebug(aState, gDebug);
+ }
+}
+#endif
+
+#ifdef DEBUG_LAYOUT
+void
+nsBox::GetBoxName(nsAutoString& aName)
+{
+ aName.AssignLiteral("Box");
+}
+#endif
+
+nsresult
+nsBox::BeginXULLayout(nsBoxLayoutState& aState)
+{
+#ifdef DEBUG_LAYOUT
+
+ nsBoxAddIndents();
+ printf("XULLayout: ");
+ XULDumpBox(stdout);
+ printf("\n");
+ gIndent++;
+#endif
+
+ // mark ourselves as dirty so no child under us
+ // can post an incremental layout.
+ // XXXldb Is this still needed?
+ mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
+
+ if (GetStateBits() & NS_FRAME_IS_DIRTY)
+ {
+ // If the parent is dirty, all the children are dirty (ReflowInput
+ // does this too).
+ nsIFrame* box;
+ for (box = GetChildXULBox(this); box; box = GetNextXULBox(box))
+ box->AddStateBits(NS_FRAME_IS_DIRTY);
+ }
+
+ // Another copy-over from ReflowInput.
+ // Since we are in reflow, we don't need to store these properties anymore.
+ FrameProperties props = Properties();
+ props.Delete(UsedBorderProperty());
+ props.Delete(UsedPaddingProperty());
+ props.Delete(UsedMarginProperty());
+
+#ifdef DEBUG_LAYOUT
+ PropagateDebug(aState);
+#endif
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBox::DoXULLayout(nsBoxLayoutState& aState)
+{
+ return NS_OK;
+}
+
+nsresult
+nsBox::EndXULLayout(nsBoxLayoutState& aState)
+{
+
+ #ifdef DEBUG_LAYOUT
+ --gIndent;
+ #endif
+
+ return SyncLayout(aState);
+}
+
+bool nsBox::gGotTheme = false;
+nsITheme* nsBox::gTheme = nullptr;
+
+nsBox::nsBox()
+{
+ MOZ_COUNT_CTOR(nsBox);
+ //mX = 0;
+ //mY = 0;
+ if (!gGotTheme) {
+ gGotTheme = true;
+ CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme);
+ }
+}
+
+nsBox::~nsBox()
+{
+ // NOTE: This currently doesn't get called for |nsBoxToBlockAdaptor|
+ // objects, so don't rely on putting anything here.
+ MOZ_COUNT_DTOR(nsBox);
+}
+
+/* static */ void
+nsBox::Shutdown()
+{
+ gGotTheme = false;
+ NS_IF_RELEASE(gTheme);
+}
+
+nsresult
+nsBox::XULRelayoutChildAtOrdinal(nsIFrame* aChild)
+{
+ return NS_OK;
+}
+
+nsresult
+nsIFrame::GetXULClientRect(nsRect& aClientRect)
+{
+ aClientRect = mRect;
+ aClientRect.MoveTo(0,0);
+
+ nsMargin borderPadding;
+ GetXULBorderAndPadding(borderPadding);
+
+ aClientRect.Deflate(borderPadding);
+
+ if (aClientRect.width < 0)
+ aClientRect.width = 0;
+
+ if (aClientRect.height < 0)
+ aClientRect.height = 0;
+
+ // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0");
+
+ return NS_OK;
+}
+
+void
+nsBox::SetXULBounds(nsBoxLayoutState& aState, const nsRect& aRect, bool aRemoveOverflowAreas)
+{
+ NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetXULBounds Size < 0");
+
+ nsRect rect(mRect);
+
+ uint32_t flags = GetXULLayoutFlags();
+
+ uint32_t stateFlags = aState.LayoutFlags();
+
+ flags |= stateFlags;
+
+ if ((flags & NS_FRAME_NO_MOVE_FRAME) == NS_FRAME_NO_MOVE_FRAME)
+ SetSize(aRect.Size());
+ else
+ SetRect(aRect);
+
+ // Nuke the overflow area. The caller is responsible for restoring
+ // it if necessary.
+ if (aRemoveOverflowAreas) {
+ // remove the previously stored overflow area
+ ClearOverflowRects();
+ }
+
+ if (!(flags & NS_FRAME_NO_MOVE_VIEW))
+ {
+ nsContainerFrame::PositionFrameView(this);
+ if ((rect.x != aRect.x) || (rect.y != aRect.y))
+ nsContainerFrame::PositionChildViews(this);
+ }
+
+
+ /*
+ // only if the origin changed
+ if ((rect.x != aRect.x) || (rect.y != aRect.y)) {
+ if (frame->HasView()) {
+ nsContainerFrame::PositionFrameView(presContext, frame,
+ frame->GetView());
+ } else {
+ nsContainerFrame::PositionChildViews(presContext, frame);
+ }
+ }
+ */
+}
+
+nsresult
+nsIFrame::GetXULBorderAndPadding(nsMargin& aBorderAndPadding)
+{
+ aBorderAndPadding.SizeTo(0, 0, 0, 0);
+ nsresult rv = GetXULBorder(aBorderAndPadding);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsMargin padding;
+ rv = GetXULPadding(padding);
+ if (NS_FAILED(rv))
+ return rv;
+
+ aBorderAndPadding += padding;
+
+ return rv;
+}
+
+nsresult
+nsBox::GetXULBorder(nsMargin& aMargin)
+{
+ aMargin.SizeTo(0,0,0,0);
+
+ const nsStyleDisplay* disp = StyleDisplay();
+ if (disp->mAppearance && gTheme) {
+ // Go to the theme for the border.
+ nsPresContext *context = PresContext();
+ if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
+ nsIntMargin margin(0, 0, 0, 0);
+ gTheme->GetWidgetBorder(context->DeviceContext(), this,
+ disp->mAppearance, &margin);
+ aMargin.top = context->DevPixelsToAppUnits(margin.top);
+ aMargin.right = context->DevPixelsToAppUnits(margin.right);
+ aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
+ aMargin.left = context->DevPixelsToAppUnits(margin.left);
+ return NS_OK;
+ }
+ }
+
+ aMargin = StyleBorder()->GetComputedBorder();
+
+ return NS_OK;
+}
+
+nsresult
+nsBox::GetXULPadding(nsMargin& aMargin)
+{
+ const nsStyleDisplay *disp = StyleDisplay();
+ if (disp->mAppearance && gTheme) {
+ // Go to the theme for the padding.
+ nsPresContext *context = PresContext();
+ if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) {
+ nsIntMargin margin(0, 0, 0, 0);
+ bool useThemePadding;
+
+ useThemePadding = gTheme->GetWidgetPadding(context->DeviceContext(),
+ this, disp->mAppearance,
+ &margin);
+ if (useThemePadding) {
+ aMargin.top = context->DevPixelsToAppUnits(margin.top);
+ aMargin.right = context->DevPixelsToAppUnits(margin.right);
+ aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
+ aMargin.left = context->DevPixelsToAppUnits(margin.left);
+ return NS_OK;
+ }
+ }
+ }
+
+ aMargin.SizeTo(0,0,0,0);
+ StylePadding()->GetPadding(aMargin);
+
+ return NS_OK;
+}
+
+nsresult
+nsBox::GetXULMargin(nsMargin& aMargin)
+{
+ aMargin.SizeTo(0,0,0,0);
+ StyleMargin()->GetMargin(aMargin);
+
+ return NS_OK;
+}
+
+void
+nsBox::SizeNeedsRecalc(nsSize& aSize)
+{
+ aSize.width = -1;
+ aSize.height = -1;
+}
+
+void
+nsBox::CoordNeedsRecalc(nscoord& aFlex)
+{
+ aFlex = -1;
+}
+
+bool
+nsBox::DoesNeedRecalc(const nsSize& aSize)
+{
+ return (aSize.width == -1 || aSize.height == -1);
+}
+
+bool
+nsBox::DoesNeedRecalc(nscoord aCoord)
+{
+ return (aCoord == -1);
+}
+
+nsSize
+nsBox::GetXULPrefSize(nsBoxLayoutState& aState)
+{
+ NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
+
+ nsSize pref(0,0);
+ DISPLAY_PREF_SIZE(this, pref);
+
+ if (IsXULCollapsed())
+ return pref;
+
+ AddBorderAndPadding(pref);
+ bool widthSet, heightSet;
+ nsIFrame::AddXULPrefSize(this, pref, widthSet, heightSet);
+
+ nsSize minSize = GetXULMinSize(aState);
+ nsSize maxSize = GetXULMaxSize(aState);
+ return BoundsCheck(minSize, pref, maxSize);
+}
+
+nsSize
+nsBox::GetXULMinSize(nsBoxLayoutState& aState)
+{
+ NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
+
+ nsSize min(0,0);
+ DISPLAY_MIN_SIZE(this, min);
+
+ if (IsXULCollapsed())
+ return min;
+
+ AddBorderAndPadding(min);
+ bool widthSet, heightSet;
+ nsIFrame::AddXULMinSize(aState, this, min, widthSet, heightSet);
+ return min;
+}
+
+nsSize
+nsBox::GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState)
+{
+ return nsSize(0, 0);
+}
+
+nsSize
+nsBox::GetXULMaxSize(nsBoxLayoutState& aState)
+{
+ NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
+
+ nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
+ DISPLAY_MAX_SIZE(this, maxSize);
+
+ if (IsXULCollapsed())
+ return maxSize;
+
+ AddBorderAndPadding(maxSize);
+ bool widthSet, heightSet;
+ nsIFrame::AddXULMaxSize(this, maxSize, widthSet, heightSet);
+ return maxSize;
+}
+
+nscoord
+nsBox::GetXULFlex()
+{
+ nscoord flex = 0;
+
+ nsIFrame::AddXULFlex(this, flex);
+
+ return flex;
+}
+
+uint32_t
+nsIFrame::GetXULOrdinal()
+{
+ uint32_t ordinal = StyleXUL()->mBoxOrdinal;
+
+ // When present, attribute value overrides CSS.
+ nsIContent* content = GetContent();
+ if (content && content->IsXULElement()) {
+ nsresult error;
+ nsAutoString value;
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, value);
+ if (!value.IsEmpty()) {
+ ordinal = value.ToInteger(&error);
+ }
+ }
+
+ return ordinal;
+}
+
+nscoord
+nsBox::GetXULBoxAscent(nsBoxLayoutState& aState)
+{
+ if (IsXULCollapsed())
+ return 0;
+
+ return GetXULPrefSize(aState).height;
+}
+
+bool
+nsBox::IsXULCollapsed()
+{
+ return StyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE;
+}
+
+nsresult
+nsIFrame::XULLayout(nsBoxLayoutState& aState)
+{
+ NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
+
+ nsBox *box = static_cast<nsBox*>(this);
+ DISPLAY_LAYOUT(box);
+
+ box->BeginXULLayout(aState);
+
+ box->DoXULLayout(aState);
+
+ box->EndXULLayout(aState);
+
+ return NS_OK;
+}
+
+bool
+nsBox::DoesClipChildren()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+ NS_ASSERTION((display->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
+ (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
+ "If one overflow is clip, the other should be too");
+ return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP;
+}
+
+nsresult
+nsBox::SyncLayout(nsBoxLayoutState& aState)
+{
+ /*
+ if (IsXULCollapsed()) {
+ CollapseChild(aState, this, true);
+ return NS_OK;
+ }
+ */
+
+
+ if (GetStateBits() & NS_FRAME_IS_DIRTY)
+ XULRedraw(aState);
+
+ RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY
+ | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW);
+
+ nsPresContext* presContext = aState.PresContext();
+
+ uint32_t flags = GetXULLayoutFlags();
+
+ uint32_t stateFlags = aState.LayoutFlags();
+
+ flags |= stateFlags;
+
+ nsRect visualOverflow;
+
+ if (ComputesOwnOverflowArea()) {
+ visualOverflow = GetVisualOverflowRect();
+ }
+ else {
+ nsRect rect(nsPoint(0, 0), GetSize());
+ nsOverflowAreas overflowAreas(rect, rect);
+ if (!DoesClipChildren() && !IsXULCollapsed()) {
+ // See if our child frames caused us to overflow after being laid
+ // out. If so, store the overflow area. This normally can't happen
+ // in XUL, but it can happen with the CSS 'outline' property and
+ // possibly with other exotic stuff (e.g. relatively positioned
+ // frames in HTML inside XUL).
+ nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
+ }
+
+ FinishAndStoreOverflow(overflowAreas, GetSize());
+ visualOverflow = overflowAreas.VisualOverflow();
+ }
+
+ nsView* view = GetView();
+ if (view) {
+ // Make sure the frame's view is properly sized and positioned and has
+ // things like opacity correct
+ nsContainerFrame::SyncFrameViewAfterReflow(presContext, this, view,
+ visualOverflow, flags);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsIFrame::XULRedraw(nsBoxLayoutState& aState)
+{
+ if (aState.PaintingDisabled())
+ return NS_OK;
+
+ // nsStackLayout, at least, expects us to repaint descendants even
+ // if a damage rect is provided
+ InvalidateFrameSubtree();
+
+ return NS_OK;
+}
+
+bool
+nsIFrame::AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
+{
+ aWidthSet = false;
+ aHeightSet = false;
+
+ // add in the css min, max, pref
+ const nsStylePosition* position = aBox->StylePosition();
+
+ // see if the width or height was specifically set
+ // XXX Handle eStyleUnit_Enumerated?
+ // (Handling the eStyleUnit_Enumerated types requires
+ // GetXULPrefSize/GetXULMinSize methods that don't consider
+ // (min-/max-/)(width/height) properties.)
+ const nsStyleCoord &width = position->mWidth;
+ if (width.GetUnit() == eStyleUnit_Coord) {
+ aSize.width = width.GetCoordValue();
+ aWidthSet = true;
+ } else if (width.IsCalcUnit()) {
+ if (!width.CalcHasPercent()) {
+ // pass 0 for percentage basis since we know there are no %s
+ aSize.width = nsRuleNode::ComputeComputedCalc(width, 0);
+ if (aSize.width < 0)
+ aSize.width = 0;
+ aWidthSet = true;
+ }
+ }
+
+ const nsStyleCoord &height = position->mHeight;
+ if (height.GetUnit() == eStyleUnit_Coord) {
+ aSize.height = height.GetCoordValue();
+ aHeightSet = true;
+ } else if (height.IsCalcUnit()) {
+ if (!height.CalcHasPercent()) {
+ // pass 0 for percentage basis since we know there are no %s
+ aSize.height = nsRuleNode::ComputeComputedCalc(height, 0);
+ if (aSize.height < 0)
+ aSize.height = 0;
+ aHeightSet = true;
+ }
+ }
+
+ nsIContent* content = aBox->GetContent();
+ // ignore 'height' and 'width' attributes if the actual element is not XUL
+ // For example, we might be magic XUL frames whose primary content is an HTML
+ // <select>
+ if (content && content->IsXULElement()) {
+ nsAutoString value;
+ nsresult error;
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value);
+ if (!value.IsEmpty()) {
+ value.Trim("%");
+
+ aSize.width =
+ nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
+ aWidthSet = true;
+ }
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::height, value);
+ if (!value.IsEmpty()) {
+ value.Trim("%");
+
+ aSize.height =
+ nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
+ aHeightSet = true;
+ }
+ }
+
+ return (aWidthSet && aHeightSet);
+}
+
+
+bool
+nsIFrame::AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize,
+ bool &aWidthSet, bool &aHeightSet)
+{
+ aWidthSet = false;
+ aHeightSet = false;
+
+ bool canOverride = true;
+
+ // See if a native theme wants to supply a minimum size.
+ const nsStyleDisplay* display = aBox->StyleDisplay();
+ if (display->mAppearance) {
+ nsITheme *theme = aState.PresContext()->GetTheme();
+ if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) {
+ LayoutDeviceIntSize size;
+ theme->GetMinimumWidgetSize(aState.PresContext(), aBox,
+ display->mAppearance, &size, &canOverride);
+ if (size.width) {
+ aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width);
+ aWidthSet = true;
+ }
+ if (size.height) {
+ aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height);
+ aHeightSet = true;
+ }
+ }
+ }
+
+ // add in the css min, max, pref
+ const nsStylePosition* position = aBox->StylePosition();
+
+ // same for min size. Unfortunately min size is always set to 0. So for now
+ // we will assume 0 (as a coord) means not set.
+ const nsStyleCoord &minWidth = position->mMinWidth;
+ if ((minWidth.GetUnit() == eStyleUnit_Coord &&
+ minWidth.GetCoordValue() != 0) ||
+ (minWidth.IsCalcUnit() && !minWidth.CalcHasPercent())) {
+ nscoord min = nsRuleNode::ComputeCoordPercentCalc(minWidth, 0);
+ if (!aWidthSet || (min > aSize.width && canOverride)) {
+ aSize.width = min;
+ aWidthSet = true;
+ }
+ } else if (minWidth.GetUnit() == eStyleUnit_Percent) {
+ NS_ASSERTION(minWidth.GetPercentValue() == 0.0f,
+ "Non-zero percentage values not currently supported");
+ aSize.width = 0;
+ aWidthSet = true; // FIXME: should we really do this for
+ // nonzero values?
+ }
+ // XXX Handle eStyleUnit_Enumerated?
+ // (Handling the eStyleUnit_Enumerated types requires
+ // GetXULPrefSize/GetXULMinSize methods that don't consider
+ // (min-/max-/)(width/height) properties.
+ // calc() with percentage is treated like '0' (unset)
+
+ const nsStyleCoord &minHeight = position->mMinHeight;
+ if ((minHeight.GetUnit() == eStyleUnit_Coord &&
+ minHeight.GetCoordValue() != 0) ||
+ (minHeight.IsCalcUnit() && !minHeight.CalcHasPercent())) {
+ nscoord min = nsRuleNode::ComputeCoordPercentCalc(minHeight, 0);
+ if (!aHeightSet || (min > aSize.height && canOverride)) {
+ aSize.height = min;
+ aHeightSet = true;
+ }
+ } else if (minHeight.GetUnit() == eStyleUnit_Percent) {
+ NS_ASSERTION(position->mMinHeight.GetPercentValue() == 0.0f,
+ "Non-zero percentage values not currently supported");
+ aSize.height = 0;
+ aHeightSet = true; // FIXME: should we really do this for
+ // nonzero values?
+ }
+ // calc() with percentage is treated like '0' (unset)
+
+ nsIContent* content = aBox->GetContent();
+ if (content && content->IsXULElement()) {
+ nsAutoString value;
+ nsresult error;
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::minwidth, value);
+ if (!value.IsEmpty())
+ {
+ value.Trim("%");
+
+ nscoord val =
+ nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
+ if (val > aSize.width)
+ aSize.width = val;
+ aWidthSet = true;
+ }
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value);
+ if (!value.IsEmpty())
+ {
+ value.Trim("%");
+
+ nscoord val =
+ nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
+ if (val > aSize.height)
+ aSize.height = val;
+
+ aHeightSet = true;
+ }
+ }
+
+ return (aWidthSet && aHeightSet);
+}
+
+bool
+nsIFrame::AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
+{
+ aWidthSet = false;
+ aHeightSet = false;
+
+ // add in the css min, max, pref
+ const nsStylePosition* position = aBox->StylePosition();
+
+ // and max
+ // see if the width or height was specifically set
+ // XXX Handle eStyleUnit_Enumerated?
+ // (Handling the eStyleUnit_Enumerated types requires
+ // GetXULPrefSize/GetXULMinSize methods that don't consider
+ // (min-/max-/)(width/height) properties.)
+ const nsStyleCoord maxWidth = position->mMaxWidth;
+ if (maxWidth.ConvertsToLength()) {
+ aSize.width = nsRuleNode::ComputeCoordPercentCalc(maxWidth, 0);
+ aWidthSet = true;
+ }
+ // percentages and calc() with percentages are treated like 'none'
+
+ const nsStyleCoord &maxHeight = position->mMaxHeight;
+ if (maxHeight.ConvertsToLength()) {
+ aSize.height = nsRuleNode::ComputeCoordPercentCalc(maxHeight, 0);
+ aHeightSet = true;
+ }
+ // percentages and calc() with percentages are treated like 'none'
+
+ nsIContent* content = aBox->GetContent();
+ if (content && content->IsXULElement()) {
+ nsAutoString value;
+ nsresult error;
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth, value);
+ if (!value.IsEmpty()) {
+ value.Trim("%");
+
+ nscoord val =
+ nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
+ aSize.width = val;
+ aWidthSet = true;
+ }
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxheight, value);
+ if (!value.IsEmpty()) {
+ value.Trim("%");
+
+ nscoord val =
+ nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
+ aSize.height = val;
+
+ aHeightSet = true;
+ }
+ }
+
+ return (aWidthSet || aHeightSet);
+}
+
+bool
+nsIFrame::AddXULFlex(nsIFrame* aBox, nscoord& aFlex)
+{
+ bool flexSet = false;
+
+ // get the flexibility
+ aFlex = aBox->StyleXUL()->mBoxFlex;
+
+ // attribute value overrides CSS
+ nsIContent* content = aBox->GetContent();
+ if (content && content->IsXULElement()) {
+ nsresult error;
+ nsAutoString value;
+
+ content->GetAttr(kNameSpaceID_None, nsGkAtoms::flex, value);
+ if (!value.IsEmpty()) {
+ value.Trim("%");
+ aFlex = value.ToInteger(&error);
+ flexSet = true;
+ }
+ }
+
+ if (aFlex < 0)
+ aFlex = 0;
+ if (aFlex >= nscoord_MAX)
+ aFlex = nscoord_MAX - 1;
+
+ return flexSet || aFlex > 0;
+}
+
+void
+nsBox::AddBorderAndPadding(nsSize& aSize)
+{
+ AddBorderAndPadding(this, aSize);
+}
+
+void
+nsBox::AddBorderAndPadding(nsIFrame* aBox, nsSize& aSize)
+{
+ nsMargin borderPadding(0,0,0,0);
+ aBox->GetXULBorderAndPadding(borderPadding);
+ AddMargin(aSize, borderPadding);
+}
+
+void
+nsBox::AddMargin(nsIFrame* aChild, nsSize& aSize)
+{
+ nsMargin margin(0,0,0,0);
+ aChild->GetXULMargin(margin);
+ AddMargin(aSize, margin);
+}
+
+void
+nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin)
+{
+ if (aSize.width != NS_INTRINSICSIZE)
+ aSize.width += aMargin.left + aMargin.right;
+
+ if (aSize.height != NS_INTRINSICSIZE)
+ aSize.height += aMargin.top + aMargin.bottom;
+}
+
+nscoord
+nsBox::BoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax)
+{
+ if (aPref > aMax)
+ aPref = aMax;
+
+ if (aPref < aMin)
+ aPref = aMin;
+
+ return aPref;
+}
+
+nsSize
+nsBox::BoundsCheckMinMax(const nsSize& aMinSize, const nsSize& aMaxSize)
+{
+ return nsSize(std::max(aMaxSize.width, aMinSize.width),
+ std::max(aMaxSize.height, aMinSize.height));
+}
+
+nsSize
+nsBox::BoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize, const nsSize& aMaxSize)
+{
+ return nsSize(BoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width),
+ BoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height));
+}
+
+/*static*/ nsIFrame*
+nsBox::GetChildXULBox(const nsIFrame* aFrame)
+{
+ // box layout ends at box-wrapped frames, so don't allow these frames
+ // to report child boxes.
+ return aFrame->IsXULBoxFrame() ? aFrame->PrincipalChildList().FirstChild() : nullptr;
+}
+
+/*static*/ nsIFrame*
+nsBox::GetNextXULBox(const nsIFrame* aFrame)
+{
+ return aFrame->GetParent() &&
+ aFrame->GetParent()->IsXULBoxFrame() ? aFrame->GetNextSibling() : nullptr;
+}
+
+/*static*/ nsIFrame*
+nsBox::GetParentXULBox(const nsIFrame* aFrame)
+{
+ return aFrame->GetParent() &&
+ aFrame->GetParent()->IsXULBoxFrame() ? aFrame->GetParent() : nullptr;
+}
+
+#ifdef DEBUG_LAYOUT
+nsresult
+nsBox::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBox::GetDebugBoxAt( const nsPoint& aPoint,
+ nsIFrame** aBox)
+{
+ nsRect thisRect(nsPoint(0,0), GetSize());
+ if (!thisRect.Contains(aPoint))
+ return NS_ERROR_FAILURE;
+
+ nsIFrame* child = nsBox::GetChildXULBox(this);
+ nsIFrame* hit = nullptr;
+
+ *aBox = nullptr;
+ while (nullptr != child) {
+ nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit);
+
+ if (NS_SUCCEEDED(rv) && hit) {
+ *aBox = hit;
+ }
+ child = GetNextXULBox(child);
+ }
+
+ // found a child
+ if (*aBox) {
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+
+nsresult
+nsBox::GetXULDebug(bool& aDebug)
+{
+ aDebug = false;
+ return NS_OK;
+}
+
+#endif