Bug 1698043 - Simplify <input type=number/search> layout to fix this bug and make ::-moz-complex-control-wrapper unnecessary. r=dholbert

This should be a simpler setup. We keep every element being a direct
anon child of the text control, and special case the reflow of the
spinners / clear button, to subtract that size from the other elements.

This fixes the bug by ensuring that the editor and placeholder are sized
and positioned in exactly the same way.

Differential Revision: https://phabricator.services.mozilla.com/D108305
This commit is contained in:
Emilio Cobos Álvarez
2021-03-14 07:53:13 +00:00
parent f86e8182e8
commit 07daf219da
17 changed files with 128 additions and 137 deletions

View File

@@ -149,13 +149,7 @@ void nsTextControlFrame::DestroyFrom(nsIFrame* aDestructRoot,
// If we're a subclass like nsNumberControlFrame, then it owns the root of the
// anonymous subtree where mRootNode is.
if (mClass == kClassID) {
aPostDestroyData.AddAnonymousContent(mRootNode.forget());
} else {
MOZ_ASSERT(!mRootNode || !mRootNode->IsRootOfNativeAnonymousSubtree());
mRootNode = nullptr;
}
aPostDestroyData.AddAnonymousContent(mRootNode.forget());
aPostDestroyData.AddAnonymousContent(mPlaceholderDiv.forget());
aPostDestroyData.AddAnonymousContent(mPreviewDiv.forget());
@@ -636,9 +630,10 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
aDesiredSize.SetOverflowAreasToDesiredBounds();
// perform reflow on all kids
nsIFrame* kid = mFrames.FirstChild();
nscoord buttonBoxISize = 0;
while (kid) {
ReflowTextControlChild(kid, aPresContext, aReflowInput, aStatus,
aDesiredSize);
aDesiredSize, buttonBoxISize);
kid = kid->GetNextSibling();
}
@@ -652,37 +647,74 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
void nsTextControlFrame::ReflowTextControlChild(
nsIFrame* aKid, nsPresContext* aPresContext,
const ReflowInput& aReflowInput, nsReflowStatus& aStatus,
ReflowOutput& aParentDesiredSize) {
ReflowOutput& aParentDesiredSize, nscoord& aButtonBoxISize) {
const WritingMode outerWM = aReflowInput.GetWritingMode();
// compute available size and frame offsets for child
WritingMode wm = aKid->GetWritingMode();
const WritingMode wm = aKid->GetWritingMode();
LogicalSize availSize = aReflowInput.ComputedSizeWithPadding(wm);
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
const bool isButtonBox =
aKid->Style()->GetPseudoType() == PseudoStyleType::mozNumberSpinBox ||
aKid->Style()->GetPseudoType() == PseudoStyleType::mozSearchClearButton;
ReflowInput kidReflowInput(aPresContext, aReflowInput, aKid, availSize,
Nothing(), ReflowInput::InitFlag::CallerWillInit);
// Override padding with our computed padding in case we got it from theming
// or percentage.
kidReflowInput.Init(aPresContext, Nothing(), Nothing(),
Some(aReflowInput.ComputedLogicalPadding(wm)));
// or percentage, if we're not the button box.
auto overridePadding =
isButtonBox ? Nothing() : Some(aReflowInput.ComputedLogicalPadding(wm));
kidReflowInput.Init(aPresContext, Nothing(), Nothing(), overridePadding);
// Set computed width and computed height for the child
kidReflowInput.SetComputedWidth(aReflowInput.ComputedWidth());
kidReflowInput.SetComputedHeight(aReflowInput.ComputedHeight());
LogicalPoint position(wm);
const auto& bp = aReflowInput.ComputedLogicalBorderPadding(outerWM);
// Offset the frame by the size of the parent's border
nscoord xOffset = aReflowInput.ComputedPhysicalBorderPadding().left -
aReflowInput.ComputedPhysicalPadding().left;
nscoord yOffset = aReflowInput.ComputedPhysicalBorderPadding().top -
aReflowInput.ComputedPhysicalPadding().top;
if (!isButtonBox) {
MOZ_ASSERT(wm == outerWM,
"Shouldn't have to care about orthogonal "
"writing-modes and such inside the control, "
"except for the number spin-box which forces "
"horizontal-tb");
// Offset the frame by the size of the parent's border
const auto& padding = aReflowInput.ComputedLogicalPadding(wm);
position.B(wm) = bp.BStart(wm) - padding.BStart(wm);
position.I(wm) = bp.IStart(wm) - padding.IStart(wm);
// Set computed width and computed height for the child (the button box is
// the only exception, which has an auto size).
kidReflowInput.SetComputedISize(
std::max(0, aReflowInput.ComputedISize() - aButtonBoxISize));
kidReflowInput.SetComputedBSize(aReflowInput.ComputedBSize());
}
// reflow the child
ReflowOutput desiredSize(aReflowInput);
ReflowChild(aKid, aPresContext, desiredSize, kidReflowInput, xOffset, yOffset,
ReflowChildFlags::Default, aStatus);
const nsSize containerSize =
aReflowInput.ComputedSizeWithBorderPadding(outerWM).GetPhysicalSize(
outerWM);
ReflowChild(aKid, aPresContext, desiredSize, kidReflowInput, wm, position,
containerSize, ReflowChildFlags::Default, aStatus);
if (isButtonBox) {
auto size = desiredSize.Size(outerWM);
// Center button in the block axis of our content box. We do this
// computation in terms of outerWM for simplicity.
position = LogicalPoint(outerWM);
position.B(outerWM) =
bp.BStart(outerWM) +
(aReflowInput.ComputedBSize() - size.BSize(outerWM)) / 2;
// Align to the inline-end of the content box.
position.I(outerWM) =
bp.IStart(outerWM) + aReflowInput.ComputedISize() - size.ISize(outerWM);
position = position.ConvertTo(wm, outerWM, containerSize);
aButtonBoxISize = size.ISize(outerWM);
}
// place the child
FinishReflowChild(aKid, aPresContext, desiredSize, &kidReflowInput, xOffset,
yOffset, ReflowChildFlags::Default);
FinishReflowChild(aKid, aPresContext, desiredSize, &kidReflowInput, wm,
position, containerSize, ReflowChildFlags::Default);
// consider the overflow
aParentDesiredSize.mOverflowAreas.UnionWith(desiredSize.mOverflowAreas);