commit 1a9bdcf11bfa91d9b63d512da6a317aa5f0e05d3
parent 194051e8a7f99d6f2882c127b32db5503666b4ef
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Thu, 9 Oct 2025 11:53:49 +0000
Bug 1993353 - Remove NS_FRAME_INDEPENDENT_SELECTION. r=layout-reviewers,dshin
It's only used to check the closest text control. We can abuse the fact
that nsTextControlFrame only has anonymous kids instead to make checking
for a containing text control fast in the common case.
Differential Revision: https://phabricator.services.mozilla.com/D268110
Diffstat:
6 files changed, 32 insertions(+), 40 deletions(-)
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
@@ -217,7 +217,7 @@ nsIContent::IMEState nsIContent::GetDesiredIMEState() {
bool nsIContent::HasIndependentSelection() const {
nsIFrame* frame = GetPrimaryFrame();
- return (frame && frame->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION));
+ return frame && frame->IsInsideTextControl();
}
dom::Element* nsIContent::GetEditingHost() const {
diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp
@@ -380,8 +380,6 @@ nsresult nsTextControlFrame::CreateAnonymousContent(
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript());
MOZ_ASSERT(mContent, "We should have a content!");
- AddStateBits(NS_FRAME_INDEPENDENT_SELECTION);
-
RefPtr<TextControlElement> textControlElement = ControlElement();
mRootNode = MakeAnonElement(PseudoStyleType::mozTextControlEditingRoot);
if (NS_WARN_IF(!mRootNode)) {
diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h
@@ -144,9 +144,6 @@ FRAME_STATE_BIT(Generic, 11, NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
// PresShell::FrameNeedsReflow. Pass the right arguments instead.
FRAME_STATE_BIT(Generic, 12, NS_FRAME_HAS_DIRTY_CHILDREN)
-// If this bit is set, the frame was created from anonymous content.
-FRAME_STATE_BIT(Generic, 14, NS_FRAME_INDEPENDENT_SELECTION)
-
// If this bit is set, the frame is part of the mangled frame hierarchy
// that results when an inline has been split because of a nested block.
// See the comments in nsCSSFrameConstructor::ConstructInline for
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
@@ -633,7 +633,6 @@ void nsIFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
(NS_FRAME_GENERATED_CONTENT |
NS_FRAME_OUT_OF_FLOW |
NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN |
- NS_FRAME_INDEPENDENT_SELECTION |
NS_FRAME_PART_OF_IBSPLIT |
NS_FRAME_MAY_BE_TRANSFORMED |
NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR));
@@ -662,7 +661,6 @@ void nsIFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
// clang-format off
AddStateBits(GetParent()->GetStateBits() &
(NS_FRAME_GENERATED_CONTENT |
- NS_FRAME_INDEPENDENT_SELECTION |
NS_FRAME_IS_SVG_TEXT |
NS_FRAME_IN_POPUP |
NS_FRAME_IS_NONDISPLAY));
@@ -2399,6 +2397,22 @@ already_AddRefed<ComputedStyle> nsIFrame::ComputeTargetTextStyle() const {
return pseudoStyle.forget();
}
+nsTextControlFrame* nsIFrame::GetContainingTextControlFrame() const {
+ const nsIFrame* cur = this;
+ do {
+ if (const nsTextControlFrame* tc = do_QueryFrame(cur)) {
+ return const_cast<nsTextControlFrame*>(tc);
+ }
+ auto* content = cur->GetContent();
+ if (!content || !content->IsInNativeAnonymousSubtree()) {
+ // All content inside text controls is anonymous.
+ return nullptr;
+ }
+ cur = cur->GetParent();
+ } while (cur);
+ return nullptr;
+}
+
bool nsIFrame::CanBeDynamicReflowRoot() const {
const auto& display = *StyleDisplay();
if (IsLineParticipant() || display.mDisplay.IsRuby() ||
@@ -5674,26 +5688,16 @@ static bool SelfIsSelectable(nsIFrame* aFrame, nsIFrame* aParentFrame,
}
static bool FrameContentCanHaveParentSelectionRange(nsIFrame* aFrame) {
- // If we are only near (not directly over) then don't traverse
- // frames with independent selection (e.g. text and list controls, see bug
- // 268497). Note that this prevents any of the users of this method from
- // entering form controls.
+ // If we are only near (not directly over) then don't traverse frames with
+ // independent selection (e.g. text controls, see bug 268497). Note that this
+ // prevents any of the users of this method from entering form controls.
// XXX We might want some way to allow using the up-arrow to go into a form
// control, but the focus didn't work right anyway; it'd probably be enough
// if the left and right arrows could enter textboxes (which I don't believe
// they can at the moment)
if (aFrame->IsTextInputFrame()) {
- MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION));
return false;
}
-
- // Failure in this assertion means a new type of frame forms the root of an
- // NS_FRAME_INDEPENDENT_SELECTION subtree. In such case, the condition above
- // should be changed to handle it.
- MOZ_ASSERT_IF(
- aFrame->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION),
- aFrame->GetParent()->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION));
-
return !aFrame->IsGeneratedContentFrame();
}
@@ -9111,15 +9115,9 @@ nsresult nsIFrame::GetSelectionController(nsPresContext* aPresContext,
if (!aPresContext || !aSelCon) {
return NS_ERROR_INVALID_ARG;
}
-
- nsIFrame* frame = this;
- while (frame && frame->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION)) {
- if (nsTextControlFrame* tcf = do_QueryFrame(frame)) {
- return tcf->GetOwnedSelectionController(aSelCon);
- }
- frame = frame->GetParent();
+ if (nsTextControlFrame* tcf = GetContainingTextControlFrame()) {
+ return tcf->GetOwnedSelectionController(aSelCon);
}
-
*aSelCon = do_AddRef(aPresContext->PresShell()).take();
return NS_OK;
}
@@ -9131,14 +9129,9 @@ already_AddRefed<nsFrameSelection> nsIFrame::GetFrameSelection() {
}
const nsFrameSelection* nsIFrame::GetConstFrameSelection() const {
- nsIFrame* frame = const_cast<nsIFrame*>(this);
- while (frame && frame->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION)) {
- if (nsTextControlFrame* tcf = do_QueryFrame(frame)) {
- return tcf->GetOwnedFrameSelection();
- }
- frame = frame->GetParent();
+ if (nsTextControlFrame* tcf = GetContainingTextControlFrame()) {
+ return tcf->GetOwnedFrameSelection();
}
-
return PresShell()->ConstFrameSelection();
}
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
@@ -112,6 +112,7 @@ class nsFrameSelection;
class nsIWidget;
class nsISelectionController;
class nsILineIterator;
+class nsTextControlFrame;
class gfxSkipChars;
class gfxSkipCharsIterator;
class gfxContext;
@@ -738,8 +739,7 @@ class nsIFrame : public nsQueryFrame {
NS_DECL_QUERYFRAME
NS_DECL_QUERYFRAME_TARGET(nsIFrame)
- explicit nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
- ClassID aID)
+ nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, ClassID aID)
: mContent(nullptr),
mComputedStyle(aStyle),
mPresContext(aPresContext),
@@ -1050,6 +1050,11 @@ class nsIFrame : public nsQueryFrame {
bool CanBeDynamicReflowRoot() const;
+ // Whether we're inside an nsTextControlFrame. This is needed because that
+ // frame manages its own selection.
+ nsTextControlFrame* GetContainingTextControlFrame() const;
+ bool IsInsideTextControl() const { return !!GetContainingTextControlFrame(); }
+
/**
* Gets the parent of a frame, using the parent of the placeholder for
* out-of-flow frames.
diff --git a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
@@ -1021,8 +1021,7 @@ bool nsTypeAheadFind::IsRangeVisible(nsRange* aRange, bool aMustBeInViewPort,
// Detect if we are _inside_ a text control, or something else with its own
// selection controller.
if (aUsesIndependentSelection) {
- *aUsesIndependentSelection =
- frame->HasAnyStateBits(NS_FRAME_INDEPENDENT_SELECTION);
+ *aUsesIndependentSelection = frame->IsInsideTextControl();
}
return aMustBeInViewPort ? IsRangeRendered(aRange) : true;