Bug 1943226 - Make nsFrameSelection treat limiters are elements r=jjaschke,dom-core
`nsFrameSelection::GetLimiter()` is not `nullptr` only when it's an instance for an independent selection of a text control. In the case, it's set to the editor root anonymous `<div>` of the text control. Despite the name, this is already optimized only for this purpose in `nsFrameSelection::NodeIsInLimiters()`. Thus, we don't have any problems to make this clearer for the other developers with renaming some parameter names. `nsFrameSelection::GetAncestorLimiter()` is also always an `Element`. So, we can change this to `Element` too. Differential Revision: https://phabricator.services.mozilla.com/D235254
This commit is contained in:
@@ -2179,7 +2179,7 @@ nsresult Selection::GetCachedFrameOffset(nsIFrame* aFrame, int32_t inOffset,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* Selection::GetAncestorLimiter() const {
|
Element* Selection::GetAncestorLimiter() const {
|
||||||
MOZ_ASSERT(mSelectionType == SelectionType::eNormal);
|
MOZ_ASSERT(mSelectionType == SelectionType::eNormal);
|
||||||
|
|
||||||
if (mFrameSelection) {
|
if (mFrameSelection) {
|
||||||
@@ -2188,7 +2188,7 @@ nsIContent* Selection::GetAncestorLimiter() const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection::SetAncestorLimiter(nsIContent* aLimiter) {
|
void Selection::SetAncestorLimiter(Element* aLimiter) {
|
||||||
if (NeedsToLogSelectionAPI(*this)) {
|
if (NeedsToLogSelectionAPI(*this)) {
|
||||||
LogSelectionAPI(this, __FUNCTION__, "aLimiter", aLimiter);
|
LogSelectionAPI(this, __FUNCTION__, "aLimiter", aLimiter);
|
||||||
LogStackForSelectionAPI();
|
LogStackForSelectionAPI();
|
||||||
|
|||||||
@@ -783,8 +783,8 @@ class Selection final : public nsSupportsWeakReference,
|
|||||||
const TextRangeStyle& aTextRangeStyle);
|
const TextRangeStyle& aTextRangeStyle);
|
||||||
|
|
||||||
// Methods to manipulate our mFrameSelection's ancestor limiter.
|
// Methods to manipulate our mFrameSelection's ancestor limiter.
|
||||||
nsIContent* GetAncestorLimiter() const;
|
Element* GetAncestorLimiter() const;
|
||||||
void SetAncestorLimiter(nsIContent* aLimiter);
|
void SetAncestorLimiter(Element* aLimiter);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Frame Offset cache can be used just during calling
|
* Frame Offset cache can be used just during calling
|
||||||
|
|||||||
@@ -364,8 +364,7 @@ nsresult ContentEventHandler::InitRootContent(
|
|||||||
if (!aNormalSelection.RangeCount()) {
|
if (!aNormalSelection.RangeCount()) {
|
||||||
// If there is no selection range, we should compute the selection root
|
// If there is no selection range, we should compute the selection root
|
||||||
// from ancestor limiter or root content of the document.
|
// from ancestor limiter or root content of the document.
|
||||||
mRootElement =
|
mRootElement = aNormalSelection.GetAncestorLimiter();
|
||||||
Element::FromNodeOrNull(aNormalSelection.GetAncestorLimiter());
|
|
||||||
if (!mRootElement) {
|
if (!mRootElement) {
|
||||||
mRootElement = mDocument->GetRootElement();
|
mRootElement = mDocument->GetRootElement();
|
||||||
if (NS_WARN_IF(!mRootElement)) {
|
if (NS_WARN_IF(!mRootElement)) {
|
||||||
|
|||||||
@@ -339,7 +339,8 @@ class TextInputSelectionController final : public nsSupportsWeakReference,
|
|||||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(TextInputSelectionController,
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(TextInputSelectionController,
|
||||||
nsISelectionController)
|
nsISelectionController)
|
||||||
|
|
||||||
TextInputSelectionController(PresShell* aPresShell, nsIContent* aLimiter);
|
TextInputSelectionController(PresShell* aPresShell,
|
||||||
|
Element& aEditorRootAnonymousDiv);
|
||||||
|
|
||||||
void SetScrollContainerFrame(ScrollContainerFrame* aScrollContainerFrame);
|
void SetScrollContainerFrame(ScrollContainerFrame* aScrollContainerFrame);
|
||||||
nsFrameSelection* GetConstFrameSelection() { return mFrameSelection; }
|
nsFrameSelection* GetConstFrameSelection() { return mFrameSelection; }
|
||||||
@@ -401,12 +402,12 @@ NS_INTERFACE_MAP_END
|
|||||||
NS_IMPL_CYCLE_COLLECTION_WEAK(TextInputSelectionController, mFrameSelection)
|
NS_IMPL_CYCLE_COLLECTION_WEAK(TextInputSelectionController, mFrameSelection)
|
||||||
|
|
||||||
TextInputSelectionController::TextInputSelectionController(
|
TextInputSelectionController::TextInputSelectionController(
|
||||||
PresShell* aPresShell, nsIContent* aLimiter) {
|
PresShell* aPresShell, Element& aEditorRootAnonymousDiv) {
|
||||||
if (aPresShell) {
|
if (aPresShell) {
|
||||||
bool accessibleCaretEnabled =
|
const bool accessibleCaretEnabled = PresShell::AccessibleCaretEnabled(
|
||||||
PresShell::AccessibleCaretEnabled(aLimiter->OwnerDoc()->GetDocShell());
|
aEditorRootAnonymousDiv.OwnerDoc()->GetDocShell());
|
||||||
mFrameSelection =
|
mFrameSelection = new nsFrameSelection(aPresShell, accessibleCaretEnabled,
|
||||||
new nsFrameSelection(aPresShell, aLimiter, accessibleCaretEnabled);
|
&aEditorRootAnonymousDiv);
|
||||||
mPresShellWeak = do_GetWeakReference(aPresShell);
|
mPresShellWeak = do_GetWeakReference(aPresShell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1608,14 +1609,14 @@ nsresult TextControlState::BindToFrame(nsTextControlFrame* aFrame) {
|
|||||||
|
|
||||||
mBoundFrame = aFrame;
|
mBoundFrame = aFrame;
|
||||||
|
|
||||||
Element* rootNode = aFrame->GetRootNode();
|
MOZ_ASSERT(aFrame->GetRootNode());
|
||||||
MOZ_ASSERT(rootNode);
|
Element& editorRootAnonymousDiv = *aFrame->GetRootNode();
|
||||||
|
|
||||||
PresShell* presShell = aFrame->PresContext()->GetPresShell();
|
PresShell* presShell = aFrame->PresContext()->GetPresShell();
|
||||||
MOZ_ASSERT(presShell);
|
MOZ_ASSERT(presShell);
|
||||||
|
|
||||||
// Create a SelectionController
|
// Create a SelectionController
|
||||||
mSelCon = new TextInputSelectionController(presShell, rootNode);
|
mSelCon = new TextInputSelectionController(presShell, editorRootAnonymousDiv);
|
||||||
MOZ_ASSERT(!mTextListener, "Should not overwrite the object");
|
MOZ_ASSERT(!mTextListener, "Should not overwrite the object");
|
||||||
mTextListener = new TextInputListener(mTextCtrlElement);
|
mTextListener = new TextInputListener(mTextCtrlElement);
|
||||||
|
|
||||||
@@ -1645,9 +1646,11 @@ nsresult TextControlState::BindToFrame(nsTextControlFrame* aFrame) {
|
|||||||
|
|
||||||
// Set the correct direction on the newly created root node
|
// Set the correct direction on the newly created root node
|
||||||
if (mTextEditor->IsRightToLeft()) {
|
if (mTextEditor->IsRightToLeft()) {
|
||||||
rootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, u"rtl"_ns, false);
|
editorRootAnonymousDiv.SetAttr(kNameSpaceID_None, nsGkAtoms::dir,
|
||||||
|
u"rtl"_ns, false);
|
||||||
} else if (mTextEditor->IsLeftToRight()) {
|
} else if (mTextEditor->IsLeftToRight()) {
|
||||||
rootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, u"ltr"_ns, false);
|
editorRootAnonymousDiv.SetAttr(kNameSpaceID_None, nsGkAtoms::dir,
|
||||||
|
u"ltr"_ns, false);
|
||||||
} else {
|
} else {
|
||||||
// otherwise, inherit the content node's direction
|
// otherwise, inherit the content node's direction
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -524,14 +524,14 @@ class MOZ_STACK_CLASS AutoClonedSelectionRangeArray final
|
|||||||
* Equivalent to nsFrameSelection::GetLimiter().
|
* Equivalent to nsFrameSelection::GetLimiter().
|
||||||
* NOTE: This should be called only when IsForSelection() returns true.
|
* NOTE: This should be called only when IsForSelection() returns true.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] nsIContent* GetLimiter() const {
|
[[nodiscard]] dom::Element* GetLimiter() const {
|
||||||
return mLimitersAndCaretData.mLimiter;
|
return mLimitersAndCaretData.mLimiter;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Equivalent to nsFrameSelection::GetAncestorLimiter()
|
* Equivalent to nsFrameSelection::GetAncestorLimiter()
|
||||||
* NOTE: This should be called only when IsForSelection() returns true.
|
* NOTE: This should be called only when IsForSelection() returns true.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] nsIContent* GetAncestorLimiter() const {
|
[[nodiscard]] dom::Element* GetAncestorLimiter() const {
|
||||||
return mLimitersAndCaretData.mAncestorLimiter;
|
return mLimitersAndCaretData.mAncestorLimiter;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -553,12 +553,12 @@ class MOZ_STACK_CLASS AutoClonedSelectionRangeArray final
|
|||||||
return mLimitersAndCaretData.mCaretBidiLevel;
|
return mLimitersAndCaretData.mCaretBidiLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetAncestorLimiter(const nsIContent* aSelectionAncestorLimiter) {
|
void SetAncestorLimiter(const dom::Element* aSelectionAncestorLimiter) {
|
||||||
if (mLimitersAndCaretData.mAncestorLimiter == aSelectionAncestorLimiter) {
|
if (mLimitersAndCaretData.mAncestorLimiter == aSelectionAncestorLimiter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mLimitersAndCaretData.mAncestorLimiter =
|
mLimitersAndCaretData.mAncestorLimiter =
|
||||||
const_cast<nsIContent*>(aSelectionAncestorLimiter);
|
const_cast<dom::Element*>(aSelectionAncestorLimiter);
|
||||||
if (NodeIsInLimiters(GetFocusNode())) {
|
if (NodeIsInLimiters(GetFocusNode())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5702,7 +5702,7 @@ Element* EditorBase::FindSelectionRoot(const nsINode& aNode) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EditorBase::InitializeSelectionAncestorLimit(
|
void EditorBase::InitializeSelectionAncestorLimit(
|
||||||
nsIContent& aAncestorLimit) const {
|
Element& aAncestorLimit) const {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
SelectionRef().SetAncestorLimiter(&aAncestorLimit);
|
SelectionRef().SetAncestorLimiter(&aAncestorLimit);
|
||||||
@@ -5712,7 +5712,7 @@ nsresult EditorBase::InitializeSelection(
|
|||||||
const nsINode& aOriginalEventTargetNode) {
|
const nsINode& aOriginalEventTargetNode) {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> selectionRootContent =
|
const RefPtr<Element> selectionRootContent =
|
||||||
FindSelectionRoot(aOriginalEventTargetNode);
|
FindSelectionRoot(aOriginalEventTargetNode);
|
||||||
if (!selectionRootContent) {
|
if (!selectionRootContent) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|||||||
@@ -2517,8 +2517,7 @@ class EditorBase : public nsIEditor,
|
|||||||
* has parent node. So, it's always safe to
|
* has parent node. So, it's always safe to
|
||||||
* call SetAncestorLimit() with this node.
|
* call SetAncestorLimit() with this node.
|
||||||
*/
|
*/
|
||||||
virtual void InitializeSelectionAncestorLimit(
|
virtual void InitializeSelectionAncestorLimit(Element& aAncestorLimit) const;
|
||||||
nsIContent& aAncestorLimit) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes selection and caret for the editor at getting focus. If
|
* Initializes selection and caret for the editor at getting focus. If
|
||||||
|
|||||||
@@ -1063,7 +1063,7 @@ nsresult HTMLEditor::CollapseSelectionToEndOfLastLeafNodeOfDocument() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HTMLEditor::InitializeSelectionAncestorLimit(
|
void HTMLEditor::InitializeSelectionAncestorLimit(
|
||||||
nsIContent& aAncestorLimit) const {
|
Element& aAncestorLimit) const {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
// Hack for initializing selection.
|
// Hack for initializing selection.
|
||||||
@@ -7450,7 +7450,7 @@ void HTMLEditor::NotifyEditingHostMaybeChanged() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute current editing host.
|
// Compute current editing host.
|
||||||
nsIContent* editingHost = ComputeEditingHost();
|
Element* const editingHost = ComputeEditingHost();
|
||||||
if (NS_WARN_IF(!editingHost)) {
|
if (NS_WARN_IF(!editingHost)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3505,7 +3505,7 @@ class HTMLEditor final : public EditorBase,
|
|||||||
SetHTMLBackgroundColorWithTransaction(const nsAString& aColor);
|
SetHTMLBackgroundColorWithTransaction(const nsAString& aColor);
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void InitializeSelectionAncestorLimit(
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY void InitializeSelectionAncestorLimit(
|
||||||
nsIContent& aAncestorLimit) const final;
|
Element& aAncestorLimit) const final;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the given selection span the entire document.
|
* Make the given selection span the entire document.
|
||||||
|
|||||||
@@ -939,7 +939,7 @@ void PresShell::Init(nsPresContext* aPresContext, nsViewManager* aViewManager) {
|
|||||||
mAccessibleCaretEventHub->Init();
|
mAccessibleCaretEventHub->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
mSelection = new nsFrameSelection(this, nullptr, accessibleCaretEnabled);
|
mSelection = new nsFrameSelection(this, accessibleCaretEnabled);
|
||||||
|
|
||||||
// Important: this has to happen after the selection has been set up
|
// Important: this has to happen after the selection has been set up
|
||||||
#ifdef SHOW_CARET
|
#ifdef SHOW_CARET
|
||||||
@@ -2462,7 +2462,7 @@ PresShell::CompleteMove(bool aForward, bool aExtend) {
|
|||||||
// Beware! This may flush notifications via synchronous
|
// Beware! This may flush notifications via synchronous
|
||||||
// ScrollSelectionIntoView.
|
// ScrollSelectionIntoView.
|
||||||
RefPtr<nsFrameSelection> frameSelection = mSelection;
|
RefPtr<nsFrameSelection> frameSelection = mSelection;
|
||||||
nsIContent* limiter = frameSelection->GetAncestorLimiter();
|
Element* const limiter = frameSelection->GetAncestorLimiter();
|
||||||
nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
|
nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
|
||||||
: FrameConstructor()->GetRootElementFrame();
|
: FrameConstructor()->GetRootElementFrame();
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "mozilla/IntegerRange.h"
|
#include "mozilla/IntegerRange.h"
|
||||||
#include "mozilla/Logging.h"
|
#include "mozilla/Logging.h"
|
||||||
#include "mozilla/PresShell.h"
|
#include "mozilla/PresShell.h"
|
||||||
|
#include "mozilla/PseudoStyleType.h"
|
||||||
#include "mozilla/ScrollContainerFrame.h"
|
#include "mozilla/ScrollContainerFrame.h"
|
||||||
#include "mozilla/ScrollTypes.h"
|
#include "mozilla/ScrollTypes.h"
|
||||||
#include "mozilla/StaticAnalysisFunctions.h"
|
#include "mozilla/StaticAnalysisFunctions.h"
|
||||||
@@ -218,19 +219,35 @@ bool nsFrameSelection::NodeIsInLimiters(const nsINode* aContainerNode) const {
|
|||||||
|
|
||||||
// static
|
// static
|
||||||
bool nsFrameSelection::NodeIsInLimiters(
|
bool nsFrameSelection::NodeIsInLimiters(
|
||||||
const nsINode* aContainerNode, const nsIContent* aSelectionLimiter,
|
const nsINode* aContainerNode, const Element* aSelectionLimiter,
|
||||||
const nsIContent* aSelectionAncestorLimiter) {
|
const Element* aSelectionAncestorLimiter) {
|
||||||
if (!aContainerNode) {
|
if (!aContainerNode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aSelectionLimiter && aSelectionLimiter != aContainerNode &&
|
// If there is a selection limiter, it must be the anonymous <div> of a text
|
||||||
aSelectionLimiter != aContainerNode->GetParent()) {
|
// control. The <div> should have only one Text and/or a <br>. Therefore,
|
||||||
// if newfocus == the limiter. that's ok. but if not there and not parent
|
// when it's non-nullptr, selection range containers must be the container or
|
||||||
// bad
|
// the Text in it.
|
||||||
return false; // not in the right content. tLimiter said so
|
if (aSelectionLimiter) {
|
||||||
|
MOZ_ASSERT(aSelectionLimiter->GetPseudoElementType() ==
|
||||||
|
PseudoStyleType::mozTextControlEditingRoot);
|
||||||
|
MOZ_ASSERT(aSelectionLimiter->IsHTMLElement(nsGkAtoms::div));
|
||||||
|
if (aSelectionLimiter == aContainerNode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (aSelectionLimiter == aContainerNode->GetParent()) {
|
||||||
|
NS_WARNING_ASSERTION(aContainerNode->IsText(),
|
||||||
|
ToString(*aContainerNode).c_str());
|
||||||
|
MOZ_ASSERT(aContainerNode->IsText());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX We might need to return `false` if aContainerNode is in a native
|
||||||
|
// anonymous subtree, but doing it will make it impossible to select the
|
||||||
|
// anonymous subtree text in <details>.
|
||||||
return !aSelectionAncestorLimiter ||
|
return !aSelectionAncestorLimiter ||
|
||||||
aContainerNode->IsInclusiveDescendantOf(aSelectionAncestorLimiter);
|
aContainerNode->IsInclusiveDescendantOf(aSelectionAncestorLimiter);
|
||||||
}
|
}
|
||||||
@@ -376,8 +393,9 @@ nsFrameSelection::CreateRangeExtendedToSomewhere(
|
|||||||
nsDirection aExtendDirection, nsSelectionAmount aAmount,
|
nsDirection aExtendDirection, nsSelectionAmount aAmount,
|
||||||
CaretMovementStyle aMovementStyle);
|
CaretMovementStyle aMovementStyle);
|
||||||
|
|
||||||
nsFrameSelection::nsFrameSelection(PresShell* aPresShell, nsIContent* aLimiter,
|
nsFrameSelection::nsFrameSelection(
|
||||||
const bool aAccessibleCaretEnabled) {
|
PresShell* aPresShell, const bool aAccessibleCaretEnabled,
|
||||||
|
Element* aEditorRootAnonymousDiv /* = nullptr */) {
|
||||||
for (size_t i = 0; i < std::size(mDomSelections); i++) {
|
for (size_t i = 0; i < std::size(mDomSelections); i++) {
|
||||||
mDomSelections[i] = new Selection(kPresentSelectionTypes[i], this);
|
mDomSelections[i] = new Selection(kPresentSelectionTypes[i], this);
|
||||||
}
|
}
|
||||||
@@ -389,7 +407,13 @@ nsFrameSelection::nsFrameSelection(PresShell* aPresShell, nsIContent* aLimiter,
|
|||||||
|
|
||||||
mPresShell = aPresShell;
|
mPresShell = aPresShell;
|
||||||
mDragState = false;
|
mDragState = false;
|
||||||
mLimiters.mLimiter = aLimiter;
|
|
||||||
|
MOZ_ASSERT_IF(aEditorRootAnonymousDiv,
|
||||||
|
aEditorRootAnonymousDiv->GetPseudoElementType() ==
|
||||||
|
PseudoStyleType::mozTextControlEditingRoot);
|
||||||
|
MOZ_ASSERT_IF(aEditorRootAnonymousDiv,
|
||||||
|
aEditorRootAnonymousDiv->IsHTMLElement(nsGkAtoms::div));
|
||||||
|
mLimiters.mLimiter = aEditorRootAnonymousDiv;
|
||||||
|
|
||||||
// This should only ever be initialized on the main thread, so we are OK here.
|
// This should only ever be initialized on the main thread, so we are OK here.
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
@@ -940,9 +964,8 @@ nsresult nsFrameSelection::MoveCaret(nsDirection aDirection,
|
|||||||
// static
|
// static
|
||||||
Result<PeekOffsetOptions, nsresult>
|
Result<PeekOffsetOptions, nsresult>
|
||||||
nsFrameSelection::CreatePeekOffsetOptionsForCaretMove(
|
nsFrameSelection::CreatePeekOffsetOptionsForCaretMove(
|
||||||
const nsIContent* aSelectionLimiter,
|
const Element* aSelectionLimiter, ForceEditableRegion aForceEditableRegion,
|
||||||
ForceEditableRegion aForceEditableRegion, ExtendSelection aExtendSelection,
|
ExtendSelection aExtendSelection, CaretMovementStyle aMovementStyle) {
|
||||||
CaretMovementStyle aMovementStyle) {
|
|
||||||
PeekOffsetOptions options;
|
PeekOffsetOptions options;
|
||||||
// set data using aSelectionLimiter to stop on scroll views. If we have a
|
// set data using aSelectionLimiter to stop on scroll views. If we have a
|
||||||
// limiter then we stop peeking when we hit scrollable views. If no limiter
|
// limiter then we stop peeking when we hit scrollable views. If no limiter
|
||||||
@@ -978,7 +1001,7 @@ Result<Element*, nsresult> nsFrameSelection::GetAncestorLimiterForCaretMove(
|
|||||||
|
|
||||||
MOZ_ASSERT(mPresShell->GetDocument() == content->GetComposedDoc());
|
MOZ_ASSERT(mPresShell->GetDocument() == content->GetComposedDoc());
|
||||||
|
|
||||||
Element* ancestorLimiter = Element::FromNodeOrNull(GetAncestorLimiter());
|
Element* ancestorLimiter = GetAncestorLimiter();
|
||||||
if (aSelection->IsEditorSelection()) {
|
if (aSelection->IsEditorSelection()) {
|
||||||
// If the editor has not receive `focus` event, it may have not set ancestor
|
// If the editor has not receive `focus` event, it may have not set ancestor
|
||||||
// limiter. Then, we need to compute it here for the caret move.
|
// limiter. Then, we need to compute it here for the caret move.
|
||||||
@@ -2051,9 +2074,7 @@ nsFrameSelection::CreateRangeExtendedToSomewhere(
|
|||||||
: aRange.EndRef().AsRaw(),
|
: aRange.EndRef().AsRaw(),
|
||||||
aExtendDirection, aLimitersAndCaretData.mCaretAssociationHint,
|
aExtendDirection, aLimitersAndCaretData.mCaretAssociationHint,
|
||||||
aLimitersAndCaretData.mCaretBidiLevel, aAmount, options.unwrap(),
|
aLimitersAndCaretData.mCaretBidiLevel, aAmount, options.unwrap(),
|
||||||
// FIXME: mAncestorLimiter should always be an Element, but it's not
|
aLimitersAndCaretData.mAncestorLimiter);
|
||||||
// guaranteed at build time for now.
|
|
||||||
Element::FromNodeOrNull(aLimitersAndCaretData.mAncestorLimiter));
|
|
||||||
if (result.isErr()) {
|
if (result.isErr()) {
|
||||||
return result.propagateErr();
|
return result.propagateErr();
|
||||||
}
|
}
|
||||||
@@ -3022,7 +3043,7 @@ nsresult CreateAndAddRange(nsINode* aContainer, int32_t aOffset,
|
|||||||
|
|
||||||
// End of Table Selection
|
// End of Table Selection
|
||||||
|
|
||||||
void nsFrameSelection::SetAncestorLimiter(nsIContent* aLimiter) {
|
void nsFrameSelection::SetAncestorLimiter(Element* aLimiter) {
|
||||||
if (mLimiters.mAncestorLimiter != aLimiter) {
|
if (mLimiters.mAncestorLimiter != aLimiter) {
|
||||||
mLimiters.mAncestorLimiter = aLimiter;
|
mLimiters.mAncestorLimiter = aLimiter;
|
||||||
const Selection& sel = NormalSelection();
|
const Selection& sel = NormalSelection();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "mozilla/CompactPair.h"
|
#include "mozilla/CompactPair.h"
|
||||||
#include "mozilla/EnumSet.h"
|
#include "mozilla/EnumSet.h"
|
||||||
#include "mozilla/EventForwards.h"
|
#include "mozilla/EventForwards.h"
|
||||||
|
#include "mozilla/dom/Element.h"
|
||||||
#include "mozilla/dom/Highlight.h"
|
#include "mozilla/dom/Highlight.h"
|
||||||
#include "mozilla/dom/Selection.h"
|
#include "mozilla/dom/Selection.h"
|
||||||
#include "mozilla/Result.h"
|
#include "mozilla/Result.h"
|
||||||
@@ -238,6 +239,7 @@ enum class TableSelectionMode : uint32_t {
|
|||||||
class nsFrameSelection final {
|
class nsFrameSelection final {
|
||||||
public:
|
public:
|
||||||
using CaretAssociationHint = mozilla::CaretAssociationHint;
|
using CaretAssociationHint = mozilla::CaretAssociationHint;
|
||||||
|
using Element = mozilla::dom::Element;
|
||||||
|
|
||||||
/*interfaces for addref and release and queryinterface*/
|
/*interfaces for addref and release and queryinterface*/
|
||||||
|
|
||||||
@@ -520,8 +522,8 @@ class nsFrameSelection final {
|
|||||||
[[nodiscard]] bool NodeIsInLimiters(const nsINode* aContainerNode) const;
|
[[nodiscard]] bool NodeIsInLimiters(const nsINode* aContainerNode) const;
|
||||||
|
|
||||||
[[nodiscard]] static bool NodeIsInLimiters(
|
[[nodiscard]] static bool NodeIsInLimiters(
|
||||||
const nsINode* aContainerNode, const nsIContent* aSelectionLimiter,
|
const nsINode* aContainerNode, const Element* aSelectionLimiter,
|
||||||
const nsIContent* aSelectionAncestorLimiter);
|
const Element* aSelectionAncestorLimiter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetFrameToPageSelect() returns a frame which is ancestor limit of
|
* GetFrameToPageSelect() returns a frame which is ancestor limit of
|
||||||
@@ -802,16 +804,26 @@ class nsFrameSelection final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the content node that limits the selection
|
* GetLimiter() returns the selection limiter element which is currently
|
||||||
*
|
* non-nullptr only when this instance is for an independent selection of a
|
||||||
* When searching up a nodes for parents, as in a text edit field
|
* text control. Then, this returns the editor root anonymous <div> in the
|
||||||
* in an browser page, we must stop at this node else we reach into the
|
* text control element.
|
||||||
* parent page, which is very bad!
|
|
||||||
*/
|
*/
|
||||||
nsIContent* GetLimiter() const { return mLimiters.mLimiter; }
|
Element* GetLimiter() const { return mLimiters.mLimiter; }
|
||||||
|
|
||||||
nsIContent* GetAncestorLimiter() const { return mLimiters.mAncestorLimiter; }
|
/**
|
||||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetAncestorLimiter(nsIContent* aLimiter);
|
* GetAncestorLimiter() returns the root of current selection ranges. This is
|
||||||
|
* typically the focused editing host unless it's the root element of the
|
||||||
|
* document.
|
||||||
|
*/
|
||||||
|
Element* GetAncestorLimiter() const { return mLimiters.mAncestorLimiter; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set ancestor limiter. If aLimiter is not nullptr, this adjusts all
|
||||||
|
* selection ranges into the limiter element. Thus, calling this may run
|
||||||
|
* the selection listeners.
|
||||||
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetAncestorLimiter(Element* aLimiter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetPrevNextBidiLevels will return the frames and associated Bidi levels of
|
* GetPrevNextBidiLevels will return the frames and associated Bidi levels of
|
||||||
@@ -855,13 +867,15 @@ class nsFrameSelection final {
|
|||||||
* @param aPresShell is the parameter to be used for most of the other calls
|
* @param aPresShell is the parameter to be used for most of the other calls
|
||||||
* for callbacks etc
|
* for callbacks etc
|
||||||
*
|
*
|
||||||
* @param aLimiter limits the selection to nodes with aLimiter parents
|
|
||||||
*
|
|
||||||
* @param aAccessibleCaretEnabled true if we should enable the accessible
|
* @param aAccessibleCaretEnabled true if we should enable the accessible
|
||||||
* caret.
|
* caret.
|
||||||
|
*
|
||||||
|
* @param aEditorRootAnonymousDiv if this instance is for an independent
|
||||||
|
* selection for a text control, specify this to the anonymous <div> element
|
||||||
|
* of the text control which contains only an editable Text and/or a <br>.
|
||||||
*/
|
*/
|
||||||
nsFrameSelection(mozilla::PresShell* aPresShell, nsIContent* aLimiter,
|
nsFrameSelection(mozilla::PresShell* aPresShell, bool aAccessibleCaretEnabled,
|
||||||
bool aAccessibleCaretEnabled);
|
Element* aEditorRootAnonymousDiv = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param aRequesterFuncName function name which wants to start the batch.
|
* @param aRequesterFuncName function name which wants to start the batch.
|
||||||
@@ -1005,7 +1019,7 @@ class nsFrameSelection final {
|
|||||||
|
|
||||||
enum class ForceEditableRegion : bool { No, Yes };
|
enum class ForceEditableRegion : bool { No, Yes };
|
||||||
static mozilla::Result<mozilla::PeekOffsetOptions, nsresult>
|
static mozilla::Result<mozilla::PeekOffsetOptions, nsresult>
|
||||||
CreatePeekOffsetOptionsForCaretMove(const nsIContent* aSelectionLimiter,
|
CreatePeekOffsetOptionsForCaretMove(const Element* aSelectionLimiter,
|
||||||
ForceEditableRegion aForceEditableRegion,
|
ForceEditableRegion aForceEditableRegion,
|
||||||
ExtendSelection aExtendSelection,
|
ExtendSelection aExtendSelection,
|
||||||
CaretMovementStyle aMovementStyle);
|
CaretMovementStyle aMovementStyle);
|
||||||
@@ -1019,8 +1033,8 @@ class nsFrameSelection final {
|
|||||||
* @param aSelection The selection object. Must be non-null
|
* @param aSelection The selection object. Must be non-null
|
||||||
* @return The ancestor limiter, or nullptr.
|
* @return The ancestor limiter, or nullptr.
|
||||||
*/
|
*/
|
||||||
mozilla::Result<mozilla::dom::Element*, nsresult>
|
mozilla::Result<Element*, nsresult> GetAncestorLimiterForCaretMove(
|
||||||
GetAncestorLimiterForCaretMove(mozilla::dom::Selection* aSelection) const;
|
mozilla::dom::Selection* aSelection) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CreateRangeExtendedToSomewhere() is common method to implement
|
* CreateRangeExtendedToSomewhere() is common method to implement
|
||||||
@@ -1190,10 +1204,15 @@ class nsFrameSelection final {
|
|||||||
Batching mBatching;
|
Batching mBatching;
|
||||||
|
|
||||||
struct Limiters {
|
struct Limiters {
|
||||||
// Limit selection navigation to a child of this node.
|
// Limit selection navigation to a child of this element.
|
||||||
nsCOMPtr<nsIContent> mLimiter;
|
// This is set only when the nsFrameSelection instance is for the
|
||||||
// Limit selection navigation to a descendant of this node.
|
// independent selection for a text control. If this is set, it's always
|
||||||
nsCOMPtr<nsIContent> mAncestorLimiter;
|
// the anonymous <div> of the text control element.
|
||||||
|
RefPtr<Element> mLimiter;
|
||||||
|
// Limit selection navigation to a descendant of this element.
|
||||||
|
// This is typically the focused editing host if set unless it's the root
|
||||||
|
// element of the document.
|
||||||
|
RefPtr<Element> mAncestorLimiter;
|
||||||
};
|
};
|
||||||
|
|
||||||
Limiters mLimiters;
|
Limiters mLimiters;
|
||||||
@@ -1294,6 +1313,8 @@ namespace mozilla {
|
|||||||
* A struct for sharing nsFrameSelection outside of its instance.
|
* A struct for sharing nsFrameSelection outside of its instance.
|
||||||
*/
|
*/
|
||||||
struct LimitersAndCaretData {
|
struct LimitersAndCaretData {
|
||||||
|
using Element = dom::Element;
|
||||||
|
|
||||||
LimitersAndCaretData() = default;
|
LimitersAndCaretData() = default;
|
||||||
explicit LimitersAndCaretData(const nsFrameSelection& aFrameSelection)
|
explicit LimitersAndCaretData(const nsFrameSelection& aFrameSelection)
|
||||||
: mLimiter(aFrameSelection.GetLimiter()),
|
: mLimiter(aFrameSelection.GetLimiter()),
|
||||||
@@ -1312,9 +1333,9 @@ struct LimitersAndCaretData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// nsFrameSelection::GetLimiter
|
// nsFrameSelection::GetLimiter
|
||||||
nsCOMPtr<nsIContent> mLimiter;
|
RefPtr<Element> mLimiter;
|
||||||
// nsFrameSelection::GetAncestorLimiter
|
// nsFrameSelection::GetAncestorLimiter
|
||||||
nsCOMPtr<nsIContent> mAncestorLimiter;
|
RefPtr<Element> mAncestorLimiter;
|
||||||
// nsFrameSelection::GetHint
|
// nsFrameSelection::GetHint
|
||||||
CaretAssociationHint mCaretAssociationHint = CaretAssociationHint::Before;
|
CaretAssociationHint mCaretAssociationHint = CaretAssociationHint::Before;
|
||||||
// nsFrameSelection::GetCaretBidiLevel
|
// nsFrameSelection::GetCaretBidiLevel
|
||||||
|
|||||||
Reference in New Issue
Block a user