mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 20:49:27 +00:00
Bug 1764684 - part 2: Make editor use methods of EditorBase
to collapse Selection
r=m_kato
First, move methods of `HTMLEditor` which collapse `Selection` to `EditorBase`. Then, make editor stop accessing `Selection::CollapseInLimiter` directly. Differential Revision: https://phabricator.services.mozilla.com/D143814
This commit is contained in:
parent
4fa991f17a
commit
17fc88e168
@ -183,30 +183,23 @@ NS_IMETHODIMP CompositionTransaction::UndoTransaction() {
|
||||
("%p CompositionTransaction::%s this=%s", this, __FUNCTION__,
|
||||
ToString(*this).c_str()));
|
||||
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Get the selection first so we'll fail before making any changes if we
|
||||
// can't get it
|
||||
RefPtr<Selection> selection = mEditorBase->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<Text> textNode = *mTextNode;
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
editorBase->DoDeleteText(textNode, mOffset, mStringToInsert.Length(), error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("EditorBase::DoDeleteText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
// set the selection to the insertion point where the string was removed
|
||||
nsresult rv = selection->CollapseInLimiter(textNode, mOffset);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Selection::CollapseInLimiter() failed");
|
||||
return rv;
|
||||
editorBase->CollapseSelectionTo(EditorRawDOMPoint(textNode, mOffset), error);
|
||||
NS_ASSERTION(!error.Failed(), "EditorBase::CollapseSelectionTo() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP CompositionTransaction::RedoTransaction() {
|
||||
|
@ -7,12 +7,13 @@
|
||||
|
||||
#include "DeleteNodeTransaction.h"
|
||||
#include "DeleteTextTransaction.h"
|
||||
#include "EditorBase.h"
|
||||
#include "EditorDOMPoint.h"
|
||||
#include "EditorUtils.h"
|
||||
#include "HTMLEditUtils.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ContentIterator.h"
|
||||
#include "mozilla/EditorBase.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/RangeBoundary.h"
|
||||
@ -116,13 +117,11 @@ NS_IMETHODIMP DeleteRangeTransaction::DoTransaction() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<Selection> selection = mEditorBase->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
rv = selection->CollapseInLimiter(startRef.AsRaw());
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
rv = editorBase->CollapseSelectionTo(EditorRawDOMPoint(startRef));
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -123,9 +123,9 @@ NS_IMETHODIMP DeleteTextTransaction::DoTransaction() {
|
||||
}
|
||||
|
||||
// Get the text that we're about to delete
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
mTextNode->SubstringData(mOffset, mLengthToDelete, mDeletedText, error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("Text::SubstringData() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
@ -133,7 +133,7 @@ NS_IMETHODIMP DeleteTextTransaction::DoTransaction() {
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<Text> textNode = *mTextNode;
|
||||
editorBase->DoDeleteText(textNode, mOffset, mLengthToDelete, error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("EditorBase::DoDeleteText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
@ -145,13 +145,9 @@ NS_IMETHODIMP DeleteTextTransaction::DoTransaction() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<Selection> selection = editorBase->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
selection->CollapseInLimiter(EditorRawDOMPoint(textNode, mOffset), error);
|
||||
editorBase->CollapseSelectionTo(EditorRawDOMPoint(textNode, mOffset), error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
|
@ -378,9 +378,9 @@ nsresult EditorBase::InitEditorContentAndSelection() {
|
||||
// removed by the web app and if they call `Selection::AddRange()`,
|
||||
// it may cause multiple selection ranges.
|
||||
if (!SelectionRef().RangeCount()) {
|
||||
nsresult rv = CollapseSelectionToEnd();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionToEnd() failed");
|
||||
nsresult rv = CollapseSelectionToEndOfLastLeafNode();
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -1328,18 +1328,18 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP EditorBase::BeginningOfDocument() {
|
||||
}
|
||||
if (!firstEditableLeaf) {
|
||||
// just the root node, set selection to inside the root
|
||||
nsresult rv = SelectionRef().CollapseInLimiter(rootElement, 0);
|
||||
nsresult rv = CollapseSelectionToStartOf(*rootElement);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
"EditorBase::CollapseSelectionToStartOf() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (firstEditableLeaf->IsText()) {
|
||||
// If firstEditableLeaf is text, set selection to beginning of the text
|
||||
// node.
|
||||
nsresult rv = SelectionRef().CollapseInLimiter(firstEditableLeaf, 0);
|
||||
nsresult rv = CollapseSelectionToStartOf(*firstEditableLeaf);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
"EditorBase::CollapseSelectionToStartOf() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1352,9 +1352,9 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP EditorBase::BeginningOfDocument() {
|
||||
MOZ_ASSERT(
|
||||
parent->ComputeIndexOf(firstEditableLeaf).valueOr(UINT32_MAX) == 0,
|
||||
"How come the first node isn't the left most child in its parent?");
|
||||
nsresult rv = SelectionRef().CollapseInLimiter(parent, 0);
|
||||
nsresult rv = CollapseSelectionToStartOf(*parent);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
"EditorBase::CollapseSelectionToStartOf() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1363,15 +1363,16 @@ NS_IMETHODIMP EditorBase::EndOfDocument() {
|
||||
if (NS_WARN_IF(!editActionData.CanHandle())) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
nsresult rv = CollapseSelectionToEnd();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionToEnd() failed");
|
||||
nsresult rv = CollapseSelectionToEndOfLastLeafNode();
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
|
||||
// This is low level API for XUL applcation. So, we should return raw
|
||||
// error code here.
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult EditorBase::CollapseSelectionToEnd() const {
|
||||
nsresult EditorBase::CollapseSelectionToEndOfLastLeafNode() const {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
// XXX Why doesn't this check if the document is alive?
|
||||
@ -1385,22 +1386,22 @@ nsresult EditorBase::CollapseSelectionToEnd() const {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> lastContent = rootElement;
|
||||
nsIContent* lastLeafContent = rootElement;
|
||||
if (IsTextEditor()) {
|
||||
lastContent = rootElement->GetFirstChild();
|
||||
MOZ_ASSERT(lastContent && lastContent->IsText());
|
||||
lastLeafContent = rootElement->GetFirstChild();
|
||||
MOZ_ASSERT(lastLeafContent && lastLeafContent->IsText());
|
||||
} else {
|
||||
for (nsIContent* child = lastContent->GetLastChild();
|
||||
for (nsIContent* child = lastLeafContent->GetLastChild();
|
||||
child && HTMLEditUtils::IsContainerNode(*child);
|
||||
child = child->GetLastChild()) {
|
||||
lastContent = child;
|
||||
lastLeafContent = child;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
SelectionRef().CollapseInLimiter(lastContent, lastContent->Length());
|
||||
CollapseSelectionToEndOf(OwningNonNull<nsINode>(*lastLeafContent));
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
"EditorBase::CollapseSelectionToEndOf() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1778,14 +1779,10 @@ nsresult EditorBase::PrepareToInsertContent(
|
||||
}
|
||||
}
|
||||
|
||||
IgnoredErrorResult error;
|
||||
SelectionRef().CollapseInLimiter(pointToInsert, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
return error.StealNSResult();
|
||||
nsresult rv = CollapseSelectionTo(pointToInsert);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult EditorBase::InsertTextAt(const nsAString& aStringToInsert,
|
||||
@ -3157,20 +3154,20 @@ nsresult EditorBase::SetTextNodeWithoutTransaction(const nsAString& aString,
|
||||
// We don't support undo here, so we don't really need all of the transaction
|
||||
// machinery, therefore we can run our transaction directly, breaking all of
|
||||
// the rules!
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
DoSetText(aTextNode, aString, error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("EditorBase::DoSetText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rvIgnored = SelectionRef().CollapseInLimiter(
|
||||
MOZ_KnownLive(&aTextNode), aString.Length());
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
CollapseSelectionTo(EditorRawDOMPoint(&aTextNode, aString.Length()), error);
|
||||
if (MOZ_UNLIKELY(error.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
NS_WARNING("EditorBase::CollapseSelection() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_ASSERTION(!error.Failed(),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
|
||||
RangeUpdaterRef().SelAdjReplaceText(aTextNode, 0, length, aString.Length());
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/EditAction.h" // for EditAction and EditSubAction
|
||||
#include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
|
||||
#include "mozilla/EventForwards.h" // for InputEventTargetRanges
|
||||
#include "mozilla/Likely.h" // for MOZ_UNLIKELY, MOZ_LIKELY
|
||||
#include "mozilla/Maybe.h" // for Maybe
|
||||
#include "mozilla/OwningNonNull.h" // for OwningNonNull
|
||||
#include "mozilla/TypeInState.h" // for PropItem, StyleCache
|
||||
@ -1869,10 +1870,66 @@ class EditorBase : public nsIEditor,
|
||||
static nsresult GetEndChildNode(const Selection& aSelection,
|
||||
nsIContent** aEndNode);
|
||||
|
||||
template <typename PT, typename CT>
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
CollapseSelectionTo(const EditorDOMPointBase<PT, CT>& aPoint) const {
|
||||
// We don't need to throw exception directly for a failure of updating
|
||||
// selection. Therefore, let's use IgnoredErrorResult for the performance.
|
||||
IgnoredErrorResult error;
|
||||
CollapseSelectionTo(aPoint, error);
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
MOZ_CAN_RUN_SCRIPT void CollapseSelectionTo(
|
||||
const EditorDOMPointBase<PT, CT>& aPoint, ErrorResult& aRv) const {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(!aRv.Failed());
|
||||
|
||||
if (aPoint.GetInterlinePosition() != InterlinePosition::Undefined) {
|
||||
if (MOZ_UNLIKELY(NS_FAILED(SelectionRef().SetInterlinePosition(
|
||||
aPoint.GetInterlinePosition())))) {
|
||||
NS_WARNING("Selection::SetInterlinePosition() failed");
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SelectionRef().CollapseInLimiter(aPoint, aRv);
|
||||
if (MOZ_UNLIKELY(Destroyed())) {
|
||||
NS_WARNING("Selection::CollapseInLimiter() caused destroying the editor");
|
||||
aRv.Throw(NS_ERROR_EDITOR_DESTROYED);
|
||||
return;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!aRv.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
}
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
CollapseSelectionToStartOf(nsINode& aNode) const {
|
||||
return CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0u));
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void CollapseSelectionToStartOf(nsINode& aNode,
|
||||
ErrorResult& aRv) const {
|
||||
CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0u), aRv);
|
||||
}
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
CollapseSelectionToEndOf(nsINode& aNode) const {
|
||||
return CollapseSelectionTo(EditorRawDOMPoint::AtEndOf(aNode));
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void CollapseSelectionToEndOf(nsINode& aNode,
|
||||
ErrorResult& aRv) const {
|
||||
CollapseSelectionTo(EditorRawDOMPoint::AtEndOf(aNode), aRv);
|
||||
}
|
||||
|
||||
/**
|
||||
* CollapseSelectionToEnd() collapses the selection to the end of the editor.
|
||||
* CollapseSelectionToEnd() collapses the selection to the last leaf content
|
||||
* of the editor.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult CollapseSelectionToEnd() const;
|
||||
MOZ_CAN_RUN_SCRIPT nsresult CollapseSelectionToEndOfLastLeafNode() const;
|
||||
|
||||
/**
|
||||
* AllowsTransactionsToChangeSelection() returns true if editor allows any
|
||||
|
@ -934,13 +934,16 @@ nsresult HTMLEditor::MaybeCreatePaddingBRElementForEmptyEditor() {
|
||||
}
|
||||
|
||||
// Set selection.
|
||||
SelectionRef().CollapseInLimiter(EditorRawDOMPoint(rootElement, 0),
|
||||
ignoredError);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
rv = CollapseSelectionToStartOf(*rootElement);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionToStartOf() caused destroying the "
|
||||
"editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionToStartOf() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5026,13 +5026,16 @@ nsresult HTMLEditor::DoJoinNodes(nsIContent& aContentToKeep,
|
||||
|
||||
if (allowedTransactionsToChangeSelection) {
|
||||
// Editor wants us to set selection at join point.
|
||||
DebugOnly<nsresult> rvIgnored = SelectionRef().CollapseInLimiter(
|
||||
&aContentToKeep, removingContentLength);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
DebugOnly<nsresult> rvIgnored = CollapseSelectionTo(
|
||||
EditorRawDOMPoint(&aContentToKeep, removingContentLength));
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBases::CollapseSelectionTos() failed, but ignored");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -5105,17 +5108,16 @@ Result<RefPtr<Element>, nsresult> HTMLEditor::DeleteSelectionAndCreateElement(
|
||||
MOZ_ASSERT(newElementOrError.inspect());
|
||||
|
||||
// We want the selection to be just after the new node
|
||||
EditorRawDOMPoint afterNewElement(
|
||||
EditorRawDOMPoint::After(newElementOrError.inspect()));
|
||||
const auto afterNewElement =
|
||||
EditorRawDOMPoint::After(newElementOrError.inspect());
|
||||
MOZ_ASSERT(afterNewElement.IsSetAndValid());
|
||||
IgnoredErrorResult ignoredError;
|
||||
SelectionRef().CollapseInLimiter(afterNewElement, ignoredError);
|
||||
if (ignoredError.Failed()) {
|
||||
NS_WARNING("Selection::CollapseInLimiter() failed");
|
||||
rv = CollapseSelectionTo(afterNewElement);
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
|
||||
// XXX Even if it succeeded to create new element, this returns error
|
||||
// when Selection.Collapse() fails something. This could occur with
|
||||
// when CollapseSelectionTo() fails something. This could occur with
|
||||
// mutation observer or mutation event listener.
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
return Err(rv);
|
||||
}
|
||||
return newElementOrError;
|
||||
}
|
||||
@ -5151,27 +5153,25 @@ nsresult HTMLEditor::DeleteSelectionAndPrepareToCreateNode() {
|
||||
}
|
||||
|
||||
if (atAnchor.IsStartOfContainer()) {
|
||||
EditorRawDOMPoint atAnchorContainer(atAnchor.GetContainer());
|
||||
if (NS_WARN_IF(!atAnchorContainer.IsSetAndValid())) {
|
||||
const EditorRawDOMPoint atAnchorContainer(atAnchor.GetContainer());
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!atAnchorContainer.IsSetAndValid()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
ErrorResult error;
|
||||
SelectionRef().CollapseInLimiter(atAnchorContainer, error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
return error.StealNSResult();
|
||||
nsresult rv = CollapseSelectionTo(atAnchorContainer);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (atAnchor.IsEndOfContainer()) {
|
||||
EditorRawDOMPoint afterAnchorContainer(atAnchor.GetContainer());
|
||||
if (NS_WARN_IF(!afterAnchorContainer.AdvanceOffset())) {
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!afterAnchorContainer.AdvanceOffset()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
ErrorResult error;
|
||||
SelectionRef().CollapseInLimiter(afterAnchorContainer, error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
return error.StealNSResult();
|
||||
nsresult rv = CollapseSelectionTo(afterAnchorContainer);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
SplitNodeResult splitAtAnchorResult = SplitNodeWithTransaction(atAnchor);
|
||||
|
@ -2863,39 +2863,6 @@ class HTMLEditor final : public EditorBase,
|
||||
protected: // Shouldn't be used by friend classes
|
||||
virtual ~HTMLEditor();
|
||||
|
||||
template <typename PT, typename CT>
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG nsresult
|
||||
CollapseSelectionTo(const EditorDOMPointBase<PT, CT>& aPoint) const {
|
||||
ErrorResult error;
|
||||
CollapseSelectionTo(aPoint, error);
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG void CollapseSelectionTo(
|
||||
const EditorDOMPointBase<PT, CT>& aPoint, ErrorResult& aRv) const {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(!aRv.Failed());
|
||||
|
||||
SelectionRef().CollapseInLimiter(aPoint, aRv);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
aRv = NS_ERROR_EDITOR_DESTROYED;
|
||||
return;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!aRv.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
}
|
||||
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG nsresult
|
||||
CollapseSelectionToStartOf(nsINode& aNode) {
|
||||
return CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0));
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_NEVER_INLINE_DEBUG void CollapseSelectionToStartOf(
|
||||
nsINode& aNode, ErrorResult& aRv) const {
|
||||
CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0), aRv);
|
||||
}
|
||||
|
||||
/**
|
||||
* InitEditorContentAndSelection() may insert `<br>` elements and padding
|
||||
* `<br>` elements if they are required for `<body>` or document element.
|
||||
|
@ -1989,10 +1989,14 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteTextAroundCollapsedRanges(
|
||||
const EditorDOMPoint& newCaretPosition = result.inspect();
|
||||
MOZ_ASSERT(newCaretPosition.IsSetAndValid());
|
||||
|
||||
DebugOnly<nsresult> rvIgnored = aHTMLEditor.SelectionRef().CollapseInLimiter(
|
||||
newCaretPosition.ToRawRangeBoundary());
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::Collapse() failed, but ignored");
|
||||
rv = aHTMLEditor.CollapseSelectionTo(newCaretPosition);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return EditActionHandled();
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ NS_IMETHODIMP InsertNodeTransaction::DoTransaction() {
|
||||
"EditorBase::MarkElementDirty() failed, but ignored");
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
container->InsertBefore(contentToInsert, refChild, error);
|
||||
// InsertBefore() may call MightThrowJSException() even if there is no
|
||||
// error. We don't need the flag here.
|
||||
@ -149,14 +149,10 @@ NS_IMETHODIMP InsertNodeTransaction::DoTransaction() {
|
||||
}
|
||||
|
||||
// Place the selection just after the inserted element.
|
||||
EditorRawDOMPoint afterInsertedNode(
|
||||
EditorRawDOMPoint::After(contentToInsert));
|
||||
NS_WARNING_ASSERTION(afterInsertedNode.IsSet(),
|
||||
"Failed to set after the inserted node");
|
||||
IgnoredErrorResult ignoredError;
|
||||
selection->CollapseInLimiter(afterInsertedNode, ignoredError);
|
||||
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
editorBase->CollapseSelectionTo(EditorRawDOMPoint::After(contentToInsert),
|
||||
error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -83,10 +83,12 @@ NS_IMETHODIMP InsertTextTransaction::DoTransaction() {
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DebugOnly<nsresult> rvIgnored = selection->CollapseInLimiter(
|
||||
textNode, mOffset + mStringToInsert.Length());
|
||||
DebugOnly<nsresult> rvIgnored = editorBase->CollapseSelectionTo(
|
||||
EditorRawDOMPoint(textNode, mOffset + mStringToInsert.Length()));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
// Keep handling to adjust the ranges in the range updater even if the
|
||||
// editor is destroyed.
|
||||
} else {
|
||||
// Do nothing - DOM Range gravity will adjust selection
|
||||
}
|
||||
@ -95,7 +97,8 @@ NS_IMETHODIMP InsertTextTransaction::DoTransaction() {
|
||||
editorBase->RangeUpdaterRef().SelAdjInsertText(textNode, mOffset,
|
||||
mStringToInsert.Length());
|
||||
|
||||
return NS_OK;
|
||||
return MOZ_UNLIKELY(editorBase->Destroyed()) ? NS_ERROR_EDITOR_DESTROYED
|
||||
: NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP InsertTextTransaction::UndoTransaction() {
|
||||
|
@ -43,18 +43,19 @@ NS_IMETHODIMP ReplaceTextTransaction::DoTransaction() {
|
||||
("%p ReplaceTextTransaction::%s this=%s", this, __FUNCTION__,
|
||||
ToString(*this).c_str()));
|
||||
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode) ||
|
||||
NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode))) {
|
||||
if (MOZ_UNLIKELY(
|
||||
NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode) ||
|
||||
NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode)))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<Text> textNode = *mTextNode;
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
editorBase->DoReplaceText(textNode, mOffset, mStringToBeReplaced.Length(),
|
||||
mStringToInsert, error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("EditorBase::DoReplaceText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
@ -69,17 +70,15 @@ NS_IMETHODIMP ReplaceTextTransaction::DoTransaction() {
|
||||
|
||||
// XXX Should we stop setting selection when mutation event listener
|
||||
// modifies the text node?
|
||||
RefPtr<Selection> selection = editorBase->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DebugOnly<nsresult> rvIgnored = selection->CollapseInLimiter(
|
||||
textNode, mOffset + mStringToInsert.Length());
|
||||
if (NS_WARN_IF(editorBase->Destroyed())) {
|
||||
editorBase->CollapseSelectionTo(
|
||||
EditorRawDOMPoint(textNode, mOffset + mStringToInsert.Length()), error);
|
||||
if (MOZ_UNLIKELY(error.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_ASSERTION(!error.Failed(),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -88,20 +87,21 @@ NS_IMETHODIMP ReplaceTextTransaction::UndoTransaction() {
|
||||
("%p ReplaceTextTransaction::%s this=%s", this, __FUNCTION__,
|
||||
ToString(*this).c_str()));
|
||||
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode) ||
|
||||
NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode))) {
|
||||
if (MOZ_UNLIKELY(
|
||||
NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode) ||
|
||||
NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode)))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
nsAutoString insertedString;
|
||||
mTextNode->SubstringData(mOffset, mStringToInsert.Length(), insertedString,
|
||||
error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("CharacterData::SubstringData() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
if (insertedString != mStringToInsert) {
|
||||
if (MOZ_UNLIKELY(insertedString != mStringToInsert)) {
|
||||
NS_WARNING(
|
||||
"ReplaceTextTransaction::UndoTransaction() did nothing due to "
|
||||
"unexpected text");
|
||||
@ -113,7 +113,7 @@ NS_IMETHODIMP ReplaceTextTransaction::UndoTransaction() {
|
||||
|
||||
editorBase->DoReplaceText(textNode, mOffset, mStringToInsert.Length(),
|
||||
mStringToBeReplaced, error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("EditorBase::DoReplaceText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
@ -128,17 +128,16 @@ NS_IMETHODIMP ReplaceTextTransaction::UndoTransaction() {
|
||||
|
||||
// XXX Should we stop setting selection when mutation event listener
|
||||
// modifies the text node?
|
||||
RefPtr<Selection> selection = editorBase->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DebugOnly<nsresult> rvIgnored = selection->CollapseInLimiter(
|
||||
textNode, mOffset + mStringToBeReplaced.Length());
|
||||
if (NS_WARN_IF(editorBase->Destroyed())) {
|
||||
editorBase->CollapseSelectionTo(
|
||||
EditorRawDOMPoint(textNode, mOffset + mStringToBeReplaced.Length()),
|
||||
error);
|
||||
if (MOZ_UNLIKELY(error.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_ASSERTION(!error.Failed(),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -147,20 +146,21 @@ NS_IMETHODIMP ReplaceTextTransaction::RedoTransaction() {
|
||||
("%p ReplaceTextTransaction::%s this=%s", this, __FUNCTION__,
|
||||
ToString(*this).c_str()));
|
||||
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode) ||
|
||||
NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode))) {
|
||||
if (MOZ_UNLIKELY(
|
||||
NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode) ||
|
||||
NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode)))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
nsAutoString undoneString;
|
||||
mTextNode->SubstringData(mOffset, mStringToBeReplaced.Length(), undoneString,
|
||||
error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("CharacterData::SubstringData() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
if (undoneString != mStringToBeReplaced) {
|
||||
if (MOZ_UNLIKELY(undoneString != mStringToBeReplaced)) {
|
||||
NS_WARNING(
|
||||
"ReplaceTextTransaction::RedoTransaction() did nothing due to "
|
||||
"unexpected text");
|
||||
@ -172,7 +172,7 @@ NS_IMETHODIMP ReplaceTextTransaction::RedoTransaction() {
|
||||
|
||||
editorBase->DoReplaceText(textNode, mOffset, mStringToBeReplaced.Length(),
|
||||
mStringToInsert, error);
|
||||
if (error.Failed()) {
|
||||
if (MOZ_UNLIKELY(error.Failed())) {
|
||||
NS_WARNING("EditorBase::DoReplaceText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
@ -187,17 +187,15 @@ NS_IMETHODIMP ReplaceTextTransaction::RedoTransaction() {
|
||||
|
||||
// XXX Should we stop setting selection when mutation event listener
|
||||
// modifies the text node?
|
||||
RefPtr<Selection> selection = editorBase->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DebugOnly<nsresult> rvIgnored = selection->CollapseInLimiter(
|
||||
textNode, mOffset + mStringToInsert.Length());
|
||||
if (NS_WARN_IF(editorBase->Destroyed())) {
|
||||
editorBase->CollapseSelectionTo(
|
||||
EditorRawDOMPoint(textNode, mOffset + mStringToInsert.Length()), error);
|
||||
if (MOZ_UNLIKELY(error.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_ASSERTION(!error.Failed(),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ NS_IMETHODIMP SplitNodeTransaction::DoTransaction() {
|
||||
htmlEditor->CollapseSelectionTo(
|
||||
EditorRawDOMPoint::AtEndOf(*splitNodeResult.GetNewContent()), error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Selection::CollapseInLimiter() failed");
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
|
@ -240,9 +240,9 @@ EditActionResult TextEditor::InsertLineFeedCharacterAtSelection() {
|
||||
!pointAfterInsertedLineFeed.GetChild(),
|
||||
"After inserting text into a text node, pointAfterInsertedLineFeed."
|
||||
"GetChild() should be nullptr");
|
||||
rv = SelectionRef().CollapseInLimiter(pointAfterInsertedLineFeed);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Selection::CollapseInLimiter() failed");
|
||||
rv = CollapseSelectionTo(pointAfterInsertedLineFeed);
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
|
||||
return EditActionIgnored(rv);
|
||||
}
|
||||
|
||||
@ -276,13 +276,16 @@ nsresult TextEditor::EnsureCaretNotAtEndOfTextNode() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rvIgnored = CollapseSelectionToEnd();
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
nsresult rv = CollapseSelectionToEndOfLastLeafNode();
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionToEndOfLastLeafNode() caused destroying "
|
||||
"the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"EditorBase::CollapseSelectionToEnd() failed, but ignored");
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionToEndOfLastLeafNode() failed, but ignored");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -508,25 +511,20 @@ EditActionResult TextEditor::HandleInsertText(
|
||||
// a LF, in which case make the caret attach to the next line.
|
||||
const bool endsWithLF =
|
||||
!insertionString.IsEmpty() && insertionString.Last() == nsCRT::LF;
|
||||
DebugOnly<nsresult> rvIgnored = SelectionRef().SetInterlinePosition(
|
||||
pointAfterStringInserted.SetInterlinePosition(
|
||||
endsWithLF ? InterlinePosition::StartOfNextLine
|
||||
: InterlinePosition::EndOfLine);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::SetInterlinePosition() failed, but ignored");
|
||||
|
||||
MOZ_ASSERT(
|
||||
!pointAfterStringInserted.GetChild(),
|
||||
"After inserting text into a text node, pointAfterStringInserted."
|
||||
"GetChild() should be nullptr");
|
||||
IgnoredErrorResult ignoredError;
|
||||
SelectionRef().CollapseInLimiter(pointAfterStringInserted, ignoredError);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
nsresult rv = CollapseSelectionTo(pointAfterStringInserted);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
!ignoredError.Failed(),
|
||||
"Selection::CollapseInLimiter() failed, but ignored");
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,11 @@ interface nsIEditor : nsISupports
|
||||
[can_run_script]
|
||||
void beginningOfDocument();
|
||||
|
||||
/** sets the document selection to the end of the document */
|
||||
/**
|
||||
* Sets the selection to the end of the last leaf child/descendant or the root
|
||||
* element.
|
||||
*/
|
||||
[can_run_script]
|
||||
void endOfDocument();
|
||||
|
||||
/* ------------ Node manipulation methods -------------- */
|
||||
|
Loading…
x
Reference in New Issue
Block a user