tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Mdom/base/FragmentOrElement.cpp | 2+-
Mlayout/forms/nsTextControlFrame.cpp | 2--
Mlayout/generic/nsFrameStateBits.h | 3---
Mlayout/generic/nsIFrame.cpp | 53+++++++++++++++++++++++------------------------------
Mlayout/generic/nsIFrame.h | 9+++++++--
Mtoolkit/components/typeaheadfind/nsTypeAheadFind.cpp | 3+--
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;