Backed out changeset e942a748de2d (bug 1596356) for test_largemenu.html failures CLOSED TREE

This commit is contained in:
Bogdan Tara 2020-11-03 00:43:07 +02:00
Родитель e39e950558
Коммит 71272b90c8
12 изменённых файлов: 229 добавлений и 12 удалений

Просмотреть файл

@ -45,6 +45,14 @@ interface XULElement : Element {
[SetterThrows]
attribute DOMString maxHeight;
// Position properties for
// * popups - these are screen coordinates
// * other elements - these are client coordinates relative to parent stack.
[SetterThrows]
attribute DOMString left;
[SetterThrows]
attribute DOMString top;
// Return the screen coordinates of the element.
readonly attribute long screenX;
readonly attribute long screenY;

Просмотреть файл

@ -975,6 +975,14 @@ nsChangeHint nsXULElement::GetAttributeChangeHint(const nsAtom* aAttribute,
return nsChangeHint_ReconstructFrame;
}
// if left or top changes we reflow. This will happen in xul
// containers that manage positioned children such as a stack.
if (nsGkAtoms::left == aAttribute || nsGkAtoms::top == aAttribute ||
nsGkAtoms::right == aAttribute || nsGkAtoms::bottom == aAttribute ||
nsGkAtoms::start == aAttribute || nsGkAtoms::end == aAttribute) {
return NS_STYLE_HINT_REFLOW;
}
return nsChangeHint(0);
}

Просмотреть файл

@ -451,6 +451,14 @@ class nsXULElement : public nsStyledElement {
void SetMaxHeight(const nsAString& aValue, mozilla::ErrorResult& rv) {
SetXULAttr(nsGkAtoms::maxheight, aValue, rv);
}
void GetLeft(DOMString& aValue) const { GetXULAttr(nsGkAtoms::left, aValue); }
void SetLeft(const nsAString& aValue, mozilla::ErrorResult& rv) {
SetXULAttr(nsGkAtoms::left, aValue, rv);
}
void GetTop(DOMString& aValue) const { GetXULAttr(nsGkAtoms::top, aValue); }
void SetTop(const nsAString& aValue, mozilla::ErrorResult& rv) {
SetXULAttr(nsGkAtoms::top, aValue, rv);
}
void GetTooltipText(DOMString& aValue) const {
GetXULAttr(nsGkAtoms::tooltiptext, aValue);
}

Просмотреть файл

@ -318,6 +318,7 @@ FRAME_STATE_BIT(Generic, 59, NS_FRAME_IS_IN_SINGLE_CHAR_MI)
FRAME_STATE_GROUP(Box, nsBoxFrame)
FRAME_STATE_BIT(Box, 20, NS_STATE_BOX_CHILD_RESERVED)
FRAME_STATE_BIT(Box, 21, NS_STATE_STACK_NOT_POSITIONED)
FRAME_STATE_BIT(Box, 22, NS_STATE_IS_HORIZONTAL)
FRAME_STATE_BIT(Box, 23, NS_STATE_AUTO_STRETCH)
FRAME_STATE_BIT(Box, 24, NS_STATE_IS_ROOT)

Просмотреть файл

@ -750,6 +750,7 @@ nscoord nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex,
if (box) {
size = box->GetXULPrefSize(aState);
nsIFrame::AddXULMargin(box, size);
nsGridLayout2::AddOffset(box, size);
}
row->mPref = GET_HEIGHT(size, aIsHorizontal);
@ -817,6 +818,7 @@ nscoord nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex,
if (box) {
size = box->GetXULPrefSize(aState);
nsIFrame::AddXULMargin(box, size);
nsGridLayout2::AddOffset(box, size);
}
row->mMin = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
@ -884,6 +886,7 @@ nscoord nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex,
if (box) {
size = box->GetXULPrefSize(aState);
nsIFrame::AddXULMargin(box, size);
nsGridLayout2::AddOffset(box, size);
}
row->mMax = GET_HEIGHT(size, aIsHorizontal);

Просмотреть файл

@ -32,6 +32,7 @@ nsSize nsGridCell::GetXULPrefSize(nsBoxLayoutState& aState) {
nsSize pref = mBoxInColumn->GetXULPrefSize(aState);
nsIFrame::AddXULMargin(mBoxInColumn, pref);
nsGridLayout2::AddOffset(mBoxInColumn, pref);
nsBoxLayout::AddLargestSize(sum, pref);
}
@ -40,6 +41,7 @@ nsSize nsGridCell::GetXULPrefSize(nsBoxLayoutState& aState) {
nsSize pref = mBoxInRow->GetXULPrefSize(aState);
nsIFrame::AddXULMargin(mBoxInRow, pref);
nsGridLayout2::AddOffset(mBoxInRow, pref);
nsBoxLayout::AddLargestSize(sum, pref);
}
@ -58,6 +60,7 @@ nsSize nsGridCell::GetXULMinSize(nsBoxLayoutState& aState) {
nsSize min = mBoxInColumn->GetXULMinSize(aState);
nsIFrame::AddXULMargin(mBoxInColumn, min);
nsGridLayout2::AddOffset(mBoxInColumn, min);
nsBoxLayout::AddLargestSize(sum, min);
}
@ -66,6 +69,7 @@ nsSize nsGridCell::GetXULMinSize(nsBoxLayoutState& aState) {
nsSize min = mBoxInRow->GetXULMinSize(aState);
nsIFrame::AddXULMargin(mBoxInRow, min);
nsGridLayout2::AddOffset(mBoxInRow, min);
nsBoxLayout::AddLargestSize(sum, min);
}
@ -84,6 +88,7 @@ nsSize nsGridCell::GetXULMaxSize(nsBoxLayoutState& aState) {
nsSize max = mBoxInColumn->GetXULMaxSize(aState);
nsIFrame::AddXULMargin(mBoxInColumn, max);
nsGridLayout2::AddOffset(mBoxInColumn, max);
nsBoxLayout::AddSmallestSize(sum, max);
}
@ -92,6 +97,7 @@ nsSize nsGridCell::GetXULMaxSize(nsBoxLayoutState& aState) {
nsSize max = mBoxInRow->GetXULMaxSize(aState);
nsIFrame::AddXULMargin(mBoxInRow, max);
nsGridLayout2::AddOffset(mBoxInRow, max);
nsBoxLayout::AddSmallestSize(sum, max);
}

Просмотреть файл

@ -25,6 +25,14 @@ nsresult NS_NewGridLayout2(nsBoxLayout** aNewLayout) {
return NS_OK;
}
// static
void nsGridLayout2::AddOffset(nsIFrame* aChild, nsSize& aSize) {
nsMargin offset;
GetOffset(aChild, offset);
aSize.width += offset.left;
aSize.height += offset.top;
}
NS_IMETHODIMP
nsGridLayout2::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) {
// XXX This should be set a better way!
@ -95,6 +103,7 @@ nsSize nsGridLayout2::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
}
AddXULMargin(aBox, total);
AddOffset(aBox, total);
AddLargestSize(minSize, total);
}
@ -129,6 +138,7 @@ nsSize nsGridLayout2::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
}
AddXULMargin(aBox, total);
AddOffset(aBox, total);
AddLargestSize(pref, total);
}
@ -165,6 +175,7 @@ nsSize nsGridLayout2::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
}
AddXULMargin(aBox, total);
AddOffset(aBox, total);
AddSmallestSize(maxSize, total);
}

Просмотреть файл

@ -70,6 +70,8 @@ class nsGridLayout2 final : public nsStackLayout, public nsIGridPart {
virtual nsIGridPart* AsGridPart() override { return this; }
static void AddOffset(nsIFrame* aChild, nsSize& aSize);
protected:
explicit nsGridLayout2() = default;
virtual ~nsGridLayout2() = default;

Просмотреть файл

@ -829,6 +829,9 @@ nsresult nsBoxFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
aAttribute == nsGkAtoms::align || aAttribute == nsGkAtoms::valign ||
aAttribute == nsGkAtoms::left || aAttribute == nsGkAtoms::top ||
aAttribute == nsGkAtoms::right || aAttribute == nsGkAtoms::bottom ||
aAttribute == nsGkAtoms::start || aAttribute == nsGkAtoms::end ||
aAttribute == nsGkAtoms::minwidth || aAttribute == nsGkAtoms::maxwidth ||
aAttribute == nsGkAtoms::minheight ||
aAttribute == nsGkAtoms::maxheight || aAttribute == nsGkAtoms::flex ||
@ -870,6 +873,11 @@ nsresult nsBoxFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
AddStateBits(NS_STATE_AUTO_STRETCH);
else
RemoveStateBits(NS_STATE_AUTO_STRETCH);
} else if (aAttribute == nsGkAtoms::left || aAttribute == nsGkAtoms::top ||
aAttribute == nsGkAtoms::right ||
aAttribute == nsGkAtoms::bottom ||
aAttribute == nsGkAtoms::start || aAttribute == nsGkAtoms::end) {
RemoveStateBits(NS_STATE_STACK_NOT_POSITIONED);
}
PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange,

Просмотреть файл

@ -23,6 +23,11 @@ using namespace mozilla;
nsBoxLayout* nsStackLayout::gInstance = nullptr;
#define SPECIFIED_LEFT (1 << eSideLeft)
#define SPECIFIED_RIGHT (1 << eSideRight)
#define SPECIFIED_TOP (1 << eSideTop)
#define SPECIFIED_BOTTOM (1 << eSideBottom)
nsresult NS_NewStackLayout(nsCOMPtr<nsBoxLayout>& aNewLayout) {
if (!nsStackLayout::gInstance) {
nsStackLayout::gInstance = new nsStackLayout();
@ -39,8 +44,8 @@ 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.
* Sizing: we are as wide as the widest child plus its left offset
* we are tall as the tallest child plus its top offset.
*/
nsSize nsStackLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
@ -51,6 +56,10 @@ nsSize nsStackLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsSize pref = child->GetXULPrefSize(aState);
AddXULMargin(child, pref);
nsMargin offset;
GetOffset(child, offset);
pref.width += offset.LeftRight();
pref.height += offset.TopBottom();
if (pref.width > prefSize.width) {
prefSize.width = pref.width;
@ -75,6 +84,10 @@ nsSize nsStackLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsSize min = child->GetXULMinSize(aState);
AddXULMargin(child, min);
nsMargin offset;
GetOffset(child, offset);
min.width += offset.LeftRight();
min.height += offset.TopBottom();
if (min.width > minSize.width) {
minSize.width = min.width;
@ -102,6 +115,10 @@ nsSize nsStackLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
max = nsIFrame::XULBoundsCheckMinMax(min, max);
AddXULMargin(child, max);
nsMargin offset;
GetOffset(child, offset);
max.width += offset.LeftRight();
max.height += offset.TopBottom();
if (max.width < maxSize.width) {
maxSize.width = max.width;
@ -135,6 +152,94 @@ nscoord nsStackLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState) {
return vAscent;
}
uint8_t nsStackLayout::GetOffset(nsIFrame* aChild, nsMargin& aOffset) {
aOffset = nsMargin(0, 0, 0, 0);
// get the left, right, top and bottom offsets
// As an optimization, we cache the fact that we are not positioned to avoid
// wasting time fetching attributes.
if (aChild->IsXULBoxFrame() &&
aChild->HasAnyStateBits(NS_STATE_STACK_NOT_POSITIONED)) {
return 0;
}
uint8_t offsetSpecified = 0;
nsIContent* content = aChild->GetContent();
if (content && content->IsElement()) {
bool ltr = aChild->StyleVisibility()->mDirection == StyleDirection::Ltr;
nsAutoString value;
nsresult error;
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::start, value);
if (!value.IsEmpty()) {
value.Trim("%");
if (ltr) {
aOffset.left =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_LEFT;
} else {
aOffset.right =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_RIGHT;
}
}
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::end, value);
if (!value.IsEmpty()) {
value.Trim("%");
if (ltr) {
aOffset.right =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_RIGHT;
} else {
aOffset.left =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_LEFT;
}
}
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::left, value);
if (!value.IsEmpty()) {
value.Trim("%");
aOffset.left =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_LEFT;
}
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::right, value);
if (!value.IsEmpty()) {
value.Trim("%");
aOffset.right =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_RIGHT;
}
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::top, value);
if (!value.IsEmpty()) {
value.Trim("%");
aOffset.top = nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_TOP;
}
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::bottom, value);
if (!value.IsEmpty()) {
value.Trim("%");
aOffset.bottom =
nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
offsetSpecified |= SPECIFIED_BOTTOM;
}
}
if (!offsetSpecified && aChild->IsXULBoxFrame()) {
// If no offset was specified at all, then we cache this fact to avoid
// requerying CSS or the content model.
aChild->AddStateBits(NS_STATE_STACK_NOT_POSITIONED);
}
return offsetSpecified;
}
NS_IMETHODIMP
nsStackLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsRect clientRect;
@ -165,6 +270,57 @@ nsStackLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsMargin margin;
child->GetXULMargin(margin);
// obtain our offset from the top left border of the stack's content
// box.
nsMargin offset;
uint8_t offsetSpecified = GetOffset(child, offset);
// Set the position and size based on which offsets have been specified:
// left only - offset from left edge, preferred width
// right only - offset from right edge, preferred width
// left and right - offset from left and right edges, width in between
// this neither - no offset, full width of stack
// Vertical direction is similar.
//
// Margins on the child are also included in the edge offsets
if (offsetSpecified) {
nsSize min = child->GetXULMinSize(aState);
nsSize max = child->GetXULMaxSize(aState);
if (offsetSpecified & SPECIFIED_LEFT) {
childRect.x = clientRect.x + offset.left + margin.left;
if (offsetSpecified & SPECIFIED_RIGHT) {
nscoord width =
clientRect.width - offset.LeftRight() - margin.LeftRight();
childRect.width = clamped(width, min.width, max.width);
} else {
nscoord width = child->GetXULPrefSize(aState).width;
childRect.width = clamped(width, min.width, max.width);
}
} else if (offsetSpecified & SPECIFIED_RIGHT) {
nscoord width = child->GetXULPrefSize(aState).width;
childRect.width = clamped(width, min.width, max.width);
childRect.x = clientRect.XMost() - offset.right - margin.right -
childRect.width;
}
if (offsetSpecified & SPECIFIED_TOP) {
childRect.y = clientRect.y + offset.top + margin.top;
if (offsetSpecified & SPECIFIED_BOTTOM) {
nscoord height =
clientRect.height - offset.TopBottom() - margin.TopBottom();
childRect.height = clamped(height, min.height, max.height);
} else {
nscoord height = child->GetXULPrefSize(aState).height;
childRect.height = clamped(height, min.height, max.height);
}
} else if (offsetSpecified & SPECIFIED_BOTTOM) {
nscoord height = child->GetXULPrefSize(aState).height;
childRect.height = clamped(height, min.height, max.height);
childRect.y = clientRect.YMost() - offset.bottom - margin.bottom -
childRect.height;
}
}
// Now place the child.
child->SetXULBounds(aState, childRect);
@ -176,13 +332,13 @@ nsStackLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) {
childRect.Inflate(margin);
// Did the child push back on us and get bigger?
if (childRect.width > clientRect.width) {
clientRect.width = childRect.width;
if (offset.LeftRight() + childRect.width > clientRect.width) {
clientRect.width = childRect.width + offset.LeftRight();
grow = true;
}
if (childRect.height > clientRect.height) {
clientRect.height = childRect.height;
if (offset.TopBottom() + childRect.height > clientRect.height) {
clientRect.height = childRect.height + offset.TopBottom();
grow = true;
}
}

Просмотреть файл

@ -40,6 +40,12 @@ class nsStackLayout : public nsBoxLayout {
virtual nscoord GetAscent(nsIFrame* aBox,
nsBoxLayoutState& aBoxLayoutState) override;
// get the child offsets for aChild and set them in aMargin. Returns a
// bitfield mask of the SPECIFIED_LEFT, SPECIFIED_RIGHT, SPECIFIED_TOP and
// SPECIFIED_BOTTOM offsets indicating which sides have been specified by
// attributes.
static uint8_t GetOffset(nsIFrame* aChild, nsMargin& aMargin);
private:
static nsBoxLayout* gInstance;

Просмотреть файл

@ -357,8 +357,8 @@ function testPopupMovement()
is(screenX, expectedx, gTests[gTestIndex] + " (6000, 100) x");
is(screenY, 100, gTests[gTestIndex] + " (6000, 100) y");
is(popup.getAttribute("left"), "", gTests[gTestIndex] + " left is empty after moving");
is(popup.getAttribute("top"), "", gTests[gTestIndex] + " top is empty after moving");
is(popup.left, "", gTests[gTestIndex] + " left is empty after moving");
is(popup.top, "", gTests[gTestIndex] + " top is empty after moving");
popup.setAttribute("left", "80");
popup.setAttribute("top", "82");
[screenX, screenY] = getScreenXY(popup);
@ -368,8 +368,8 @@ function testPopupMovement()
[screenX, screenY] = getScreenXY(popup);
is(screenX, 95, gTests[gTestIndex] + " move after set left and top x");
is(screenY, 98, gTests[gTestIndex] + " move after set left and top y");
is(popup.getAttribute("left"), "95", gTests[gTestIndex] + " left is set after moving");
is(popup.getAttribute("top"), "98", gTests[gTestIndex] + " top is set after moving");
is(popup.left, "95", gTests[gTestIndex] + " left is set after moving");
is(popup.top, "98", gTests[gTestIndex] + " top is set after moving");
popup.removeAttribute("left");
popup.removeAttribute("top");
@ -381,8 +381,8 @@ function testPopupMovement()
is(screenX, expectedx, gTests[gTestIndex] + " move after set left and top x to -1");
is(screenY, expectedy, gTests[gTestIndex] + " move after set left and top y to -1");
is(popup.getAttribute("left"), "", gTests[gTestIndex] + " left is not set after moving to -1");
is(popup.getAttribute("top"), "", gTests[gTestIndex] + " top is not set after moving to -1");
is(popup.left, "", gTests[gTestIndex] + " left is not set after moving to -1");
is(popup.top, "", gTests[gTestIndex] + " top is not set after moving to -1");
popup.hidePopup();
}