forked from mirrors/gecko-dev
Gijs for front-end bits, layout for the new CSS properties and the removal of nsDeckFrame / nsStackLayout, Jamie and Morgan for the a11y changes. As discussed in the bug, the main tricky part here is handling a11y correctly. For <deck>, that's trivial (just use `visibility: hidden` to hide the panels visually, while removing the unselected panels from the a11y tree). For <tabpanels> however we need to do something special. We do want to hide stuff visually, but we want to preserve the contents in the a11y tree. For that, the easiest fix is introducing a new privileged CSS property (-moz-subtree-hidden-only-visually), which takes care of not painting the frame, but marks stuff offscreen in the accessibility tree. This is not intended to be a property used widely. Other than that, the changes are relatively straight-forward, though some of the accessible/mac changes I could get a sanity-check on. Differential Revision: https://phabricator.services.mozilla.com/D157875
609 lines
18 KiB
C++
609 lines
18 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/StaticPtr.h"
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsBoxLayoutState.h"
|
|
#include "nsBoxFrame.h"
|
|
#include "nsDOMAttributeMap.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIContent.h"
|
|
#include "nsContainerFrame.h"
|
|
#include "nsNameSpaceManager.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "nsITheme.h"
|
|
#include "nsBoxLayout.h"
|
|
#include "nsLayoutUtils.h"
|
|
#include "mozilla/dom/Attr.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include <algorithm>
|
|
|
|
using namespace mozilla;
|
|
|
|
nsresult nsIFrame::BeginXULLayout(nsBoxLayoutState& aState) {
|
|
// mark ourselves as dirty so no child under us
|
|
// can post an incremental layout.
|
|
// XXXldb Is this still needed?
|
|
AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
|
|
|
|
if (HasAnyStateBits(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->MarkSubtreeDirty();
|
|
}
|
|
|
|
// Another copy-over from ReflowInput.
|
|
// Since we are in reflow, we don't need to store these properties anymore.
|
|
RemoveProperty(UsedBorderProperty());
|
|
RemoveProperty(UsedPaddingProperty());
|
|
RemoveProperty(UsedMarginProperty());
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsIFrame::EndXULLayout(nsBoxLayoutState& aState) {
|
|
return SyncXULLayout(aState);
|
|
}
|
|
|
|
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;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsIFrame::SetXULBounds(nsBoxLayoutState& aState, const nsRect& aRect,
|
|
bool aRemoveOverflowAreas) {
|
|
nsRect rect(mRect);
|
|
|
|
ReflowChildFlags flags = GetXULLayoutFlags() | aState.LayoutFlags();
|
|
|
|
if ((flags & ReflowChildFlags::NoMoveFrame) ==
|
|
ReflowChildFlags::NoMoveFrame) {
|
|
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 & ReflowChildFlags::NoMoveView)) {
|
|
nsContainerFrame::PositionFrameView(this);
|
|
if ((rect.x != aRect.x) || (rect.y != aRect.y))
|
|
nsContainerFrame::PositionChildViews(this);
|
|
}
|
|
}
|
|
|
|
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 nsIFrame::GetXULBorder(nsMargin& aBorder) {
|
|
aBorder.SizeTo(0, 0, 0, 0);
|
|
|
|
StyleAppearance appearance = StyleDisplay()->EffectiveAppearance();
|
|
if (appearance != StyleAppearance::None) {
|
|
// Go to the theme for the border.
|
|
nsPresContext* pc = PresContext();
|
|
nsITheme* theme = pc->Theme();
|
|
if (theme->ThemeSupportsWidget(pc, this, appearance)) {
|
|
LayoutDeviceIntMargin margin =
|
|
theme->GetWidgetBorder(pc->DeviceContext(), this, appearance);
|
|
aBorder =
|
|
LayoutDevicePixel::ToAppUnits(margin, pc->AppUnitsPerDevPixel());
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
aBorder = StyleBorder()->GetComputedBorder();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsIFrame::GetXULPadding(nsMargin& aBorderAndPadding) {
|
|
StyleAppearance appearance = StyleDisplay()->EffectiveAppearance();
|
|
if (appearance != StyleAppearance::None) {
|
|
// Go to the theme for the padding.
|
|
nsPresContext* pc = PresContext();
|
|
nsITheme* theme = pc->Theme();
|
|
if (theme->ThemeSupportsWidget(pc, this, appearance)) {
|
|
LayoutDeviceIntMargin padding;
|
|
bool useThemePadding = theme->GetWidgetPadding(pc->DeviceContext(), this,
|
|
appearance, &padding);
|
|
if (useThemePadding) {
|
|
aBorderAndPadding =
|
|
LayoutDevicePixel::ToAppUnits(padding, pc->AppUnitsPerDevPixel());
|
|
return NS_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
aBorderAndPadding.SizeTo(0, 0, 0, 0);
|
|
StylePadding()->GetPadding(aBorderAndPadding);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsIFrame::GetXULMargin(nsMargin& aMargin) {
|
|
aMargin.SizeTo(0, 0, 0, 0);
|
|
StyleMargin()->GetMargin(aMargin);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsIFrame::XULSizeNeedsRecalc(nsSize& aSize) {
|
|
aSize.width = -1;
|
|
aSize.height = -1;
|
|
}
|
|
|
|
void nsIFrame::XULCoordNeedsRecalc(nscoord& aCoord) { aCoord = -1; }
|
|
|
|
bool nsIFrame::XULNeedsRecalc(const nsSize& aSize) {
|
|
return (aSize.width == -1 || aSize.height == -1);
|
|
}
|
|
|
|
bool nsIFrame::XULNeedsRecalc(nscoord aCoord) { return (aCoord == -1); }
|
|
|
|
nsSize nsIFrame::GetUncachedXULPrefSize(nsBoxLayoutState& aBoxLayoutState) {
|
|
NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
|
|
"must have rendering context");
|
|
|
|
nsSize pref(0, 0);
|
|
DISPLAY_PREF_SIZE(this, pref);
|
|
|
|
if (IsXULCollapsed()) {
|
|
return pref;
|
|
}
|
|
|
|
AddXULBorderAndPadding(pref);
|
|
bool widthSet, heightSet;
|
|
nsIFrame::AddXULPrefSize(this, pref, widthSet, heightSet);
|
|
|
|
nsSize minSize = GetXULMinSize(aBoxLayoutState);
|
|
nsSize maxSize = GetXULMaxSize(aBoxLayoutState);
|
|
return XULBoundsCheck(minSize, pref, maxSize);
|
|
}
|
|
|
|
nsSize nsIFrame::GetUncachedXULMinSize(nsBoxLayoutState& aBoxLayoutState) {
|
|
NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
|
|
"must have rendering context");
|
|
|
|
nsSize min(0, 0);
|
|
DISPLAY_MIN_SIZE(this, min);
|
|
|
|
if (IsXULCollapsed()) {
|
|
return min;
|
|
}
|
|
|
|
AddXULBorderAndPadding(min);
|
|
bool widthSet, heightSet;
|
|
nsIFrame::AddXULMinSize(this, min, widthSet, heightSet);
|
|
return min;
|
|
}
|
|
|
|
nsSize nsIFrame::GetUncachedXULMaxSize(nsBoxLayoutState& aBoxLayoutState) {
|
|
NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
|
|
"must have rendering context");
|
|
|
|
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
|
DISPLAY_MAX_SIZE(this, maxSize);
|
|
|
|
if (IsXULCollapsed()) {
|
|
return maxSize;
|
|
}
|
|
|
|
AddXULBorderAndPadding(maxSize);
|
|
bool widthSet, heightSet;
|
|
nsIFrame::AddXULMaxSize(this, maxSize, widthSet, heightSet);
|
|
return maxSize;
|
|
}
|
|
|
|
bool nsIFrame::IsXULCollapsed() {
|
|
return StyleVisibility()->mVisible == StyleVisibility::Collapse;
|
|
}
|
|
|
|
nsresult nsIFrame::XULLayout(nsBoxLayoutState& aState) {
|
|
NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
|
|
|
|
nsIFrame* box = static_cast<nsIFrame*>(this);
|
|
DISPLAY_LAYOUT(box);
|
|
|
|
box->BeginXULLayout(aState);
|
|
|
|
box->DoXULLayout(aState);
|
|
|
|
box->EndXULLayout(aState);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool nsIFrame::DoesClipChildrenInBothAxes() {
|
|
const nsStyleDisplay* display = StyleDisplay();
|
|
return display->mOverflowX == StyleOverflow::Clip &&
|
|
display->mOverflowY == StyleOverflow::Clip;
|
|
}
|
|
|
|
nsresult nsIFrame::SyncXULLayout(nsBoxLayoutState& aBoxLayoutState) {
|
|
/*
|
|
if (IsXULCollapsed()) {
|
|
CollapseChild(aBoxLayoutState, this, true);
|
|
return NS_OK;
|
|
}
|
|
*/
|
|
|
|
if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) {
|
|
XULRedraw(aBoxLayoutState);
|
|
}
|
|
|
|
RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY |
|
|
NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW);
|
|
|
|
nsPresContext* presContext = aBoxLayoutState.PresContext();
|
|
|
|
ReflowChildFlags flags = GetXULLayoutFlags() | aBoxLayoutState.LayoutFlags();
|
|
|
|
nsRect inkOverflow;
|
|
|
|
if (XULComputesOwnOverflowArea()) {
|
|
inkOverflow = InkOverflowRect();
|
|
} else {
|
|
nsRect rect(nsPoint(0, 0), GetSize());
|
|
OverflowAreas overflowAreas(rect, rect);
|
|
if (!DoesClipChildrenInBothAxes() && !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());
|
|
inkOverflow = overflowAreas.InkOverflow();
|
|
}
|
|
|
|
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,
|
|
inkOverflow, flags);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsIFrame::XULRedraw(nsBoxLayoutState& aState) {
|
|
if (aState.PaintingDisabled()) return NS_OK;
|
|
|
|
// Unclear whether we could get away with just InvalidateFrame().
|
|
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 auto& width = position->mWidth;
|
|
if (width.ConvertsToLength()) {
|
|
aSize.width = std::max(0, width.ToLength());
|
|
aWidthSet = true;
|
|
}
|
|
|
|
const auto& height = position->mHeight;
|
|
if (height.ConvertsToLength()) {
|
|
aSize.height = std::max(0, height.ToLength());
|
|
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->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value);
|
|
if (!value.IsEmpty()) {
|
|
value.Trim("%");
|
|
|
|
aSize.width = nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
|
|
aWidthSet = true;
|
|
}
|
|
|
|
content->AsElement()->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(nsIFrame* aBox, nsSize& aSize, bool& aWidthSet,
|
|
bool& aHeightSet) {
|
|
aWidthSet = false;
|
|
aHeightSet = false;
|
|
|
|
bool canOverride = true;
|
|
|
|
nsPresContext* pc = aBox->PresContext();
|
|
|
|
// See if a native theme wants to supply a minimum size.
|
|
const nsStyleDisplay* display = aBox->StyleDisplay();
|
|
if (display->HasAppearance()) {
|
|
nsITheme* theme = pc->Theme();
|
|
StyleAppearance appearance = display->EffectiveAppearance();
|
|
if (theme->ThemeSupportsWidget(pc, aBox, appearance)) {
|
|
LayoutDeviceIntSize size;
|
|
theme->GetMinimumWidgetSize(pc, aBox, appearance, &size, &canOverride);
|
|
if (size.width) {
|
|
aSize.width = pc->DevPixelsToAppUnits(size.width);
|
|
aWidthSet = true;
|
|
}
|
|
if (size.height) {
|
|
aSize.height = pc->DevPixelsToAppUnits(size.height);
|
|
aHeightSet = true;
|
|
}
|
|
} else {
|
|
switch (appearance) {
|
|
case StyleAppearance::ScrollbarVertical:
|
|
case StyleAppearance::ScrollbarHorizontal: {
|
|
ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aBox);
|
|
auto sizes = theme->GetScrollbarSizes(
|
|
pc, style->StyleUIReset()->ScrollbarWidth(),
|
|
nsITheme::Overlay::No);
|
|
if (appearance == StyleAppearance::ScrollbarVertical) {
|
|
aSize.width = pc->DevPixelsToAppUnits(sizes.mVertical);
|
|
aWidthSet = true;
|
|
} else {
|
|
aSize.height = pc->DevPixelsToAppUnits(sizes.mHorizontal);
|
|
aHeightSet = true;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// add in the css min, max, pref
|
|
const nsStylePosition* position = aBox->StylePosition();
|
|
const auto& minWidth = position->mMinWidth;
|
|
if (minWidth.ConvertsToLength()) {
|
|
nscoord min = minWidth.ToLength();
|
|
if (!aWidthSet || (min > aSize.width && canOverride)) {
|
|
aSize.width = min;
|
|
aWidthSet = true;
|
|
}
|
|
} else if (minWidth.ConvertsToPercentage()) {
|
|
NS_ASSERTION(minWidth.ToPercentage() == 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 ExtremumLength?
|
|
// (Handling them requires GetXULPrefSize/GetXULMinSize methods that don't
|
|
// consider (min-/max-/)(width/height) properties.
|
|
// calc() with percentage is treated like '0' (unset)
|
|
|
|
const auto& minHeight = position->mMinHeight;
|
|
if (minHeight.ConvertsToLength()) {
|
|
nscoord min = minHeight.ToLength();
|
|
if (!aHeightSet || (min > aSize.height && canOverride)) {
|
|
aSize.height = min;
|
|
aHeightSet = true;
|
|
}
|
|
} else if (minHeight.ConvertsToPercentage()) {
|
|
NS_ASSERTION(position->mMinHeight.ToPercentage() == 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->AsElement()->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->AsElement()->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 auto& maxWidth = position->mMaxWidth;
|
|
if (maxWidth.ConvertsToLength()) {
|
|
aSize.width = maxWidth.ToLength();
|
|
aWidthSet = true;
|
|
}
|
|
// percentages and calc() with percentages are treated like 'none'
|
|
|
|
const auto& maxHeight = position->mMaxHeight;
|
|
if (maxHeight.ConvertsToLength()) {
|
|
aSize.height = maxHeight.ToLength();
|
|
aHeightSet = true;
|
|
}
|
|
// percentages and calc() with percentages are treated like 'none'
|
|
|
|
nsIContent* content = aBox->GetContent();
|
|
if (content && content->IsXULElement()) {
|
|
nsAutoString value;
|
|
nsresult error;
|
|
|
|
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth,
|
|
value);
|
|
if (!value.IsEmpty()) {
|
|
value.Trim("%");
|
|
|
|
nscoord val = nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
|
|
aSize.width = val;
|
|
aWidthSet = true;
|
|
}
|
|
|
|
content->AsElement()->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);
|
|
}
|
|
|
|
void nsIFrame::AddXULBorderAndPadding(nsSize& aSize) {
|
|
AddXULBorderAndPadding(this, aSize);
|
|
}
|
|
|
|
void nsIFrame::AddXULBorderAndPadding(nsIFrame* aBox, nsSize& aSize) {
|
|
nsMargin borderPadding(0, 0, 0, 0);
|
|
aBox->GetXULBorderAndPadding(borderPadding);
|
|
AddXULMargin(aSize, borderPadding);
|
|
}
|
|
|
|
void nsIFrame::AddXULMargin(nsIFrame* aChild, nsSize& aSize) {
|
|
nsMargin margin(0, 0, 0, 0);
|
|
aChild->GetXULMargin(margin);
|
|
AddXULMargin(aSize, margin);
|
|
}
|
|
|
|
void nsIFrame::AddXULMargin(nsSize& aSize, const nsMargin& aMargin) {
|
|
if (aSize.width != NS_UNCONSTRAINEDSIZE)
|
|
aSize.width += aMargin.left + aMargin.right;
|
|
|
|
if (aSize.height != NS_UNCONSTRAINEDSIZE)
|
|
aSize.height += aMargin.top + aMargin.bottom;
|
|
}
|
|
|
|
nscoord nsIFrame::XULBoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax) {
|
|
if (aPref > aMax) aPref = aMax;
|
|
|
|
if (aPref < aMin) aPref = aMin;
|
|
|
|
return aPref;
|
|
}
|
|
|
|
nsSize nsIFrame::XULBoundsCheckMinMax(const nsSize& aMinSize,
|
|
const nsSize& aMaxSize) {
|
|
return nsSize(std::max(aMaxSize.width, aMinSize.width),
|
|
std::max(aMaxSize.height, aMinSize.height));
|
|
}
|
|
|
|
nsSize nsIFrame::XULBoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize,
|
|
const nsSize& aMaxSize) {
|
|
return nsSize(
|
|
XULBoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width),
|
|
XULBoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height));
|
|
}
|
|
|
|
/*static*/
|
|
nsIFrame* nsIFrame::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* nsIFrame::GetNextXULBox(const nsIFrame* aFrame) {
|
|
return aFrame->GetParent() && aFrame->GetParent()->IsXULBoxFrame()
|
|
? aFrame->GetNextSibling()
|
|
: nullptr;
|
|
}
|
|
|
|
/*static*/
|
|
nsIFrame* nsIFrame::GetParentXULBox(const nsIFrame* aFrame) {
|
|
return aFrame->GetParent() && aFrame->GetParent()->IsXULBoxFrame()
|
|
? aFrame->GetParent()
|
|
: nullptr;
|
|
}
|