Bug 1707070 - Tweak text/number/search control anonymous tree DOM / paint order. r=dholbert

So that we hit-test the spinners even if they overlap with the editor
root's padding.

Differential Revision: https://phabricator.services.mozilla.com/D113251
This commit is contained in:
Emilio Cobos Álvarez
2021-04-26 16:55:32 +00:00
parent 0335e6e151
commit 637f98f983
5 changed files with 83 additions and 53 deletions

View File

@@ -405,7 +405,6 @@ nsresult nsTextControlFrame::CreateAnonymousContent(
return rv;
}
aElements.AppendElement(mRootNode);
CreatePlaceholderIfNeeded();
if (mPlaceholderDiv) {
aElements.AppendElement(mPlaceholderDiv);
@@ -415,6 +414,10 @@ nsresult nsTextControlFrame::CreateAnonymousContent(
aElements.AppendElement(mPreviewDiv);
}
// NOTE(emilio): We want the root node always after the placeholder so that
// background on the placeholder doesn't obscure the caret.
aElements.AppendElement(mRootNode);
rv = UpdateValueDisplay(false);
NS_ENSURE_SUCCESS(rv, rv);
@@ -516,8 +519,6 @@ void nsTextControlFrame::CreatePreviewIfNeeded() {
void nsTextControlFrame::AppendAnonymousContentTo(
nsTArray<nsIContent*>& aElements, uint32_t aFilter) {
aElements.AppendElement(mRootNode);
if (mPlaceholderDiv && !(aFilter & nsIContent::eSkipPlaceholderContent)) {
aElements.AppendElement(mPlaceholderDiv);
}
@@ -525,6 +526,8 @@ void nsTextControlFrame::AppendAnonymousContentTo(
if (mPreviewDiv) {
aElements.AppendElement(mPreviewDiv);
}
aElements.AppendElement(mRootNode);
}
nscoord nsTextControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
@@ -607,6 +610,12 @@ Maybe<nscoord> nsTextControlFrame::ComputeBaseline(
aReflowInput.ComputedLogicalBorderPadding(wm).BStart(wm));
}
static bool IsButtonBox(const nsIFrame* aFrame) {
auto pseudoType = aFrame->Style()->GetPseudoType();
return pseudoType == PseudoStyleType::mozNumberSpinBox ||
pseudoType == PseudoStyleType::mozSearchClearButton;
}
void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
@@ -631,12 +640,32 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
// overflow handling
aDesiredSize.SetOverflowAreasToDesiredBounds();
nsIFrame* buttonBox = [&]() -> nsIFrame* {
nsIFrame* last = mFrames.LastChild();
if (!last || !IsButtonBox(last)) {
return nullptr;
}
return last;
}();
// Reflow the button box first, so that we can use its size for the other
// frames.
nscoord buttonBoxISize = 0;
if (buttonBox) {
ReflowTextControlChild(buttonBox, aPresContext, aReflowInput, aStatus,
aDesiredSize, buttonBoxISize);
}
// perform reflow on all kids
nsIFrame* kid = mFrames.FirstChild();
nscoord buttonBoxISize = 0;
while (kid) {
ReflowTextControlChild(kid, aPresContext, aReflowInput, aStatus,
aDesiredSize, buttonBoxISize);
if (kid != buttonBox) {
MOZ_ASSERT(!IsButtonBox(kid),
"Should only have one button box, and should be last");
ReflowTextControlChild(kid, aPresContext, aReflowInput, aStatus,
aDesiredSize, buttonBoxISize);
}
kid = kid->GetNextSibling();
}
@@ -657,9 +686,7 @@ void nsTextControlFrame::ReflowTextControlChild(
LogicalSize availSize = aReflowInput.ComputedSizeWithPadding(wm);
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
const bool isButtonBox =
aKid->Style()->GetPseudoType() == PseudoStyleType::mozNumberSpinBox ||
aKid->Style()->GetPseudoType() == PseudoStyleType::mozSearchClearButton;
bool isButtonBox = IsButtonBox(aKid);
ReflowInput kidReflowInput(aPresContext, aReflowInput, aKid, availSize,
Nothing(), ReflowInput::InitFlag::CallerWillInit);
@@ -1270,12 +1297,6 @@ nsresult nsTextControlFrame::PeekOffset(nsPeekOffsetStruct* aPos) {
void nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) {
/*
* The implementation of this method is equivalent as:
* nsContainerFrame::BuildDisplayList()
* with the difference that we filter-out the placeholder frame when it
* should not be visible.
*/
DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame");
DisplayBorderBackgroundOutline(aBuilder, aLists);
@@ -1286,20 +1307,7 @@ void nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsDisplayList* content = aLists.Content();
nsDisplayListSet set(content, content, content, content, content, content);
// We build the ::placeholder first so that it renders below mRootNode which
// draws the caret and we always want that on top (bug 1637476).
//
// TODO(emilio): We should consider just changing the DOM order instead.
if (mPlaceholderDiv && mPlaceholderDiv->GetPrimaryFrame()) {
auto* kid = mPlaceholderDiv->GetPrimaryFrame();
MOZ_ASSERT(kid->GetParent() == this);
BuildDisplayListForChild(aBuilder, kid, set);
}
for (auto* kid : mFrames) {
if (kid->GetContent() == mPlaceholderDiv) {
continue; // Handled above already.
}
BuildDisplayListForChild(aBuilder, kid, set);
}
}