diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index ab33ac0c8bad..cf4204e6b344 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -5375,4 +5375,85 @@ void EditorBase::AutoEditActionDataSetter::InitializeDataTransferWithClipboard( true /* is external */, aClipboardType); } +/***************************************************************************** + * mozilla::EditorBase::TopLevelEditSubActionData + *****************************************************************************/ + +nsresult EditorBase::TopLevelEditSubActionData::AddNodeToChangedRange( + const HTMLEditor& aHTMLEditor, nsINode& aNode) { + EditorRawDOMPoint startPoint(&aNode); + EditorRawDOMPoint endPoint(&aNode); + DebugOnly advanced = endPoint.AdvanceOffset(); + NS_WARNING_ASSERTION(advanced, "Failed to set endPoint to next to aNode"); + return AddRangeToChangedRange(aHTMLEditor, startPoint, endPoint); +} + +nsresult EditorBase::TopLevelEditSubActionData::AddPointToChangedRange( + const HTMLEditor& aHTMLEditor, const EditorRawDOMPoint& aPoint) { + return AddRangeToChangedRange(aHTMLEditor, aPoint, aPoint); +} + +nsresult EditorBase::TopLevelEditSubActionData::AddRangeToChangedRange( + const HTMLEditor& aHTMLEditor, const EditorRawDOMPoint& aStart, + const EditorRawDOMPoint& aEnd) { + if (NS_WARN_IF(!aStart.IsSet()) || NS_WARN_IF(!aEnd.IsSet())) { + return NS_ERROR_INVALID_ARG; + } + + if (!aHTMLEditor.IsDescendantOfRoot(aStart.GetContainer()) || + (aStart.GetContainer() != aEnd.GetContainer() && + !aHTMLEditor.IsDescendantOfRoot(aEnd.GetContainer()))) { + return NS_OK; + } + + // If mChangedRange hasn't been set, we can just set it to `aStart` and + // `aEnd`. + if (!mChangedRange->IsPositioned()) { + nsresult rv = mChangedRange->SetStartAndEnd(aStart.ToRawRangeBoundary(), + aEnd.ToRawRangeBoundary()); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "Failed to set mChangedRange to given range"); + return rv; + } + + bool disconnected = false; + int16_t relation = mChangedRange->StartRef().IsSet() + ? nsContentUtils::ComparePoints( + mChangedRange->StartRef(), + aStart.ToRawRangeBoundary(), &disconnected) + : 1; + if (NS_WARN_IF(disconnected)) { + return NS_ERROR_FAILURE; + } + + // If aStart is before start of mChangedRange, reset the start. + if (relation > 0) { + ErrorResult error; + mChangedRange->SetStart(aStart.ToRawRangeBoundary(), error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + } + + relation = mChangedRange->EndRef().IsSet() + ? nsContentUtils::ComparePoints(mChangedRange->EndRef(), + aEnd.ToRawRangeBoundary(), + &disconnected) + : 1; + if (NS_WARN_IF(disconnected)) { + return NS_ERROR_FAILURE; + } + + // If aEnd is after end of mChangedRange, reset the end. + if (relation < 0) { + ErrorResult error; + mChangedRange->SetEnd(aEnd.ToRawRangeBoundary(), error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + } + + return NS_OK; +} + } // namespace mozilla diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h index 7b742ea49bae..83aaf398b87e 100644 --- a/editor/libeditor/EditorBase.h +++ b/editor/libeditor/EditorBase.h @@ -655,6 +655,25 @@ class EditorBase : public nsIEditor, // to restore it. bool mRestoreContentEditableCount; + /** + * Extend mChangedRange to include `aNode`. + */ + nsresult AddNodeToChangedRange(const HTMLEditor& aHTMLEditor, + nsINode& aNode); + + /** + * Extend mChangedRange to include `aPoint`. + */ + nsresult AddPointToChangedRange(const HTMLEditor& aHTMLEditor, + const EditorRawDOMPoint& aPoint); + + /** + * Extend mChangedRange to include `aStart` and `aEnd`. + */ + nsresult AddRangeToChangedRange(const HTMLEditor& aHTMLEditor, + const EditorRawDOMPoint& aStart, + const EditorRawDOMPoint& aEnd); + private: void Clear() { mDidExplicitlySetInterLine = false; diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index 2aa90d1f4189..5973c90a9654 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -200,7 +200,6 @@ HTMLEditRules::HTMLEditRules() void HTMLEditRules::InitFields() { mHTMLEditor = nullptr; mReturnInEmptyLIKillsList = true; - mUtilRange = nullptr; mJoinOffset = 0; } @@ -243,8 +242,6 @@ nsresult HTMLEditRules::Init(TextEditor* aTextEditor) { } // make a utility range for use by the listenter - mUtilRange = new nsRange(HTMLEditorRef().GetDocument()); - if (rootElement) { nsresult rv = InsertBRElementToEmptyListItemsAndTableCellsInRange( RawRangeBoundary(rootElement, 0), @@ -313,12 +310,6 @@ nsresult HTMLEditRules::BeforeEdit() { HTMLEditorRef().RangeUpdaterRef().RegisterRangeItem( HTMLEditorRef().TopLevelEditSubActionDataRef().mSelectedRange); - // Clear out mUtilRange - if (mUtilRange) { - // Ditto for mUtilRange. - mUtilRange->Reset(); - } - // Remember current inline styles for deletion and normal insertion ops bool cacheInlineStyles; switch (HTMLEditorRef().GetTopLevelEditSubAction()) { @@ -10141,77 +10132,6 @@ nsresult HTMLEditRules::ConfirmSelectionInBody() { return NS_OK; } -nsresult HTMLEditRules::UpdateDocChangeRange(nsRange* aRange) { - MOZ_ASSERT(IsEditorDataAvailable()); - - // first make sure aRange is in the document. It might not be if - // portions of our editting action involved manipulating nodes - // prior to placing them in the document (e.g., populating a list item - // before placing it in its list) - const RangeBoundary& atStart = aRange->StartRef(); - if (NS_WARN_IF(!atStart.IsSet())) { - return NS_ERROR_FAILURE; - } - if (!HTMLEditorRef().IsDescendantOfRoot(atStart.Container())) { - // Just return - we don't need to adjust - // TopLevelEditSubActionData::mChangedRange in this case - return NS_OK; - } - - // compare starts of ranges - ErrorResult error; - int16_t result = HTMLEditorRef() - .TopLevelEditSubActionDataRef() - .mChangedRange->CompareBoundaryPoints( - Range_Binding::START_TO_START, *aRange, error); - if (error.ErrorCodeIs(NS_ERROR_NOT_INITIALIZED)) { - // This will happen is TopLevelEditSubActionData::mChangedRange is non-null, - // but the range is uninitialized. In this case we'll set the start to - // aRange start. The same test won't be needed further down since after - // we've set the start the range will be collapsed to that point. - result = 1; - error.SuppressException(); - } - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - - // Positive result means TopLevelEditSubActionData::mChangedRange start is - // after aRange start. - if (result > 0) { - HTMLEditorRef().TopLevelEditSubActionDataRef().mChangedRange->SetStart( - atStart.AsRaw(), error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - } - - // compare ends of ranges - result = HTMLEditorRef() - .TopLevelEditSubActionDataRef() - .mChangedRange->CompareBoundaryPoints(Range_Binding::END_TO_END, - *aRange, error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - - // Negative result means TopLevelEditSubActionData::mChangedRange end is - // before aRange end. - if (result < 0) { - const RangeBoundary& atEnd = aRange->EndRef(); - if (NS_WARN_IF(!atEnd.IsSet())) { - return NS_ERROR_FAILURE; - } - HTMLEditorRef().TopLevelEditSubActionDataRef().mChangedRange->SetEnd( - atEnd.AsRaw(), error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - } - - return NS_OK; -} - nsresult HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode, bool aForPadding) { MOZ_ASSERT(IsEditorDataAvailable()); @@ -10260,13 +10180,10 @@ void HTMLEditRules::DidCreateNode(Element& aNewElement) { AutoSafeEditorData setData(*this, *mHTMLEditor); - // assumption that Join keeps the righthand node - IgnoredErrorResult ignoredError; - mUtilRange->SelectNode(aNewElement, ignoredError); - if (NS_WARN_IF(ignoredError.Failed())) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddNodeToChangedRange( + HTMLEditorRef(), aNewElement); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddNodeToChangedRange() failed"); } void HTMLEditRules::DidInsertNode(nsIContent& aContent) { @@ -10280,12 +10197,10 @@ void HTMLEditRules::DidInsertNode(nsIContent& aContent) { AutoSafeEditorData setData(*this, *mHTMLEditor); - IgnoredErrorResult ignoredError; - mUtilRange->SelectNode(aContent, ignoredError); - if (NS_WARN_IF(ignoredError.Failed())) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddNodeToChangedRange( + HTMLEditorRef(), aContent); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddNodeToChangedRange() failed"); } void HTMLEditRules::WillDeleteNode(nsINode& aChild) { @@ -10299,12 +10214,10 @@ void HTMLEditRules::WillDeleteNode(nsINode& aChild) { AutoSafeEditorData setData(*this, *mHTMLEditor); - IgnoredErrorResult ignoredError; - mUtilRange->SelectNode(aChild, ignoredError); - if (NS_WARN_IF(ignoredError.Failed())) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddNodeToChangedRange( + HTMLEditorRef(), aChild); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddNodeToChangedRange() failed"); } void HTMLEditRules::DidSplitNode(nsINode& aExistingRightNode, @@ -10319,12 +10232,11 @@ void HTMLEditRules::DidSplitNode(nsINode& aExistingRightNode, AutoSafeEditorData setData(*this, *mHTMLEditor); - nsresult rv = - mUtilRange->SetStartAndEnd(&aNewLeftNode, 0, &aExistingRightNode, 0); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddRangeToChangedRange( + HTMLEditorRef(), EditorRawDOMPoint(&aNewLeftNode, 0), + EditorRawDOMPoint(&aExistingRightNode, 0)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddRangeToChangedRange() failed"); } void HTMLEditRules::WillJoinNodes(nsINode& aLeftNode, nsINode& aRightNode) { @@ -10351,12 +10263,10 @@ void HTMLEditRules::DidJoinNodes(nsINode& aLeftNode, nsINode& aRightNode) { AutoSafeEditorData setData(*this, *mHTMLEditor); - // assumption that Join keeps the righthand node - nsresult rv = mUtilRange->CollapseTo(&aRightNode, mJoinOffset); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddPointToChangedRange( + HTMLEditorRef(), EditorRawDOMPoint(&aRightNode, mJoinOffset)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddPointToChangedRange() failed"); } void HTMLEditRules::DidInsertText(nsINode& aTextNode, int32_t aOffset, @@ -10371,13 +10281,11 @@ void HTMLEditRules::DidInsertText(nsINode& aTextNode, int32_t aOffset, AutoSafeEditorData setData(*this, *mHTMLEditor); - int32_t length = aString.Length(); - nsresult rv = mUtilRange->SetStartAndEnd(&aTextNode, aOffset, &aTextNode, - aOffset + length); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddRangeToChangedRange( + HTMLEditorRef(), EditorRawDOMPoint(&aTextNode, aOffset), + EditorRawDOMPoint(&aTextNode, aOffset + aString.Length())); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddRangeToChangedRange() failed"); } void HTMLEditRules::DidDeleteText(nsINode& aTextNode, int32_t aOffset, @@ -10392,11 +10300,10 @@ void HTMLEditRules::DidDeleteText(nsINode& aTextNode, int32_t aOffset, AutoSafeEditorData setData(*this, *mHTMLEditor); - nsresult rv = mUtilRange->CollapseTo(&aTextNode, aOffset); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - UpdateDocChangeRange(mUtilRange); + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddPointToChangedRange( + HTMLEditorRef(), EditorRawDOMPoint(&aTextNode, aOffset)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddPointToChangedRange() failed"); } void HTMLEditRules::WillDeleteSelection() { @@ -10410,20 +10317,13 @@ void HTMLEditRules::WillDeleteSelection() { AutoSafeEditorData setData(*this, *mHTMLEditor); - EditorRawDOMPoint startPoint = EditorBase::GetStartPoint(*SelectionRefPtr()); - if (NS_WARN_IF(!startPoint.IsSet())) { - return; - } - EditorRawDOMPoint endPoint = EditorBase::GetEndPoint(*SelectionRefPtr()); - if (NS_WARN_IF(!endPoint.IsSet())) { - return; - } - nsresult rv = mUtilRange->SetStartAndEnd(startPoint.ToRawRangeBoundary(), - endPoint.ToRawRangeBoundary()); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - UpdateDocChangeRange(mUtilRange); + // XXX Looks like that this is wrong. We delete multiple selection ranges + // once, but this adds only first range into the changed range. + DebugOnly rv = + HTMLEditorRef().TopLevelEditSubActionDataRef().AddRangeToChangedRange( + HTMLEditorRef(), EditorBase::GetStartPoint(*SelectionRefPtr()), + EditorBase::GetStartPoint(*SelectionRefPtr())); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddRangeToChangedRange() failed"); } nsresult HTMLEditRules::RemoveAlignment(nsINode& aNode, diff --git a/editor/libeditor/HTMLEditRules.h b/editor/libeditor/HTMLEditRules.h index bf32b5304533..b7ea30b9bb4c 100644 --- a/editor/libeditor/HTMLEditRules.h +++ b/editor/libeditor/HTMLEditRules.h @@ -1201,7 +1201,6 @@ class HTMLEditRules : public TextEditRules { MOZ_MUST_USE nsresult RemoveEmptyNodesInChangedRange(); nsresult SelectionEndpointInNode(nsINode* aNode, bool* aResult); - nsresult UpdateDocChangeRange(nsRange* aRange); /** * ConfirmSelectionInBody() makes sure that Selection is in editor root @@ -1327,11 +1326,8 @@ class HTMLEditRules : public TextEditRules { bool mInitialized; bool mListenerEnabled; bool mReturnInEmptyLIKillsList; - RefPtr mUtilRange; // Need to remember an int across willJoin/didJoin... uint32_t mJoinOffset; - - friend class NS_CYCLE_COLLECTION_CLASSNAME(TextEditRules); }; } // namespace mozilla diff --git a/editor/libeditor/TextEditRules.cpp b/editor/libeditor/TextEditRules.cpp index 2531170ecd62..1d53b04caecb 100644 --- a/editor/libeditor/TextEditRules.cpp +++ b/editor/libeditor/TextEditRules.cpp @@ -60,25 +60,6 @@ using namespace dom; * mozilla::TextEditRules ********************************************************/ -NS_IMPL_CYCLE_COLLECTION_CLASS(TextEditRules) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TextEditRules) - if (HTMLEditRules* htmlEditRules = tmp->AsHTMLEditRules()) { - HTMLEditRules* tmp = htmlEditRules; - NS_IMPL_CYCLE_COLLECTION_UNLINK(mUtilRange) - } -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TextEditRules) - if (HTMLEditRules* htmlEditRules = tmp->AsHTMLEditRules()) { - HTMLEditRules* tmp = htmlEditRules; - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUtilRange) - } -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextEditRules, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextEditRules, Release) - TextEditRules::TextEditRules() : mTextEditor(nullptr), mData(nullptr), diff --git a/editor/libeditor/TextEditRules.h b/editor/libeditor/TextEditRules.h index 817cdf84d8a7..fe9eeee381a2 100644 --- a/editor/libeditor/TextEditRules.h +++ b/editor/libeditor/TextEditRules.h @@ -68,8 +68,7 @@ class TextEditRules { template using OwningNonNull = OwningNonNull; - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TextEditRules) - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(TextEditRules) + NS_INLINE_DECL_REFCOUNTING(TextEditRules) TextEditRules(); diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp index 4b3983b0d680..367ac884cb11 100644 --- a/editor/libeditor/TextEditor.cpp +++ b/editor/libeditor/TextEditor.cpp @@ -109,13 +109,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TextEditor, EditorBase) if (tmp->mMaskTimer) { tmp->mMaskTimer->Cancel(); } - NS_IMPL_CYCLE_COLLECTION_UNLINK(mRules) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedDocumentEncoder) NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaskTimer) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TextEditor, EditorBase) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRules) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedDocumentEncoder) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMaskTimer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END