1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DeleteTextTransaction.h"
8 #include "HTMLEditUtils.h"
9 #include "mozilla/Assertions.h"
10 #include "mozilla/EditorBase.h"
11 #include "mozilla/EditorDOMPoint.h"
12 #include "mozilla/SelectionState.h"
13 #include "mozilla/dom/Selection.h"
16 #include "nsISupportsImpl.h"
17 #include "nsAString.h"
24 already_AddRefed
<DeleteTextTransaction
> DeleteTextTransaction::MaybeCreate(
25 EditorBase
& aEditorBase
, Text
& aTextNode
, uint32_t aOffset
,
26 uint32_t aLengthToDelete
) {
27 RefPtr
<DeleteTextTransaction
> transaction
= new DeleteTextTransaction(
28 aEditorBase
, aTextNode
, aOffset
, aLengthToDelete
);
29 return transaction
.forget();
33 already_AddRefed
<DeleteTextTransaction
>
34 DeleteTextTransaction::MaybeCreateForPreviousCharacter(EditorBase
& aEditorBase
,
37 if (NS_WARN_IF(!aOffset
)) {
42 aTextNode
.GetData(data
);
43 if (NS_WARN_IF(data
.IsEmpty())) {
48 uint32_t offset
= aOffset
- 1;
49 if (offset
&& NS_IS_SURROGATE_PAIR(data
[offset
- 1], data
[offset
])) {
53 return DeleteTextTransaction::MaybeCreate(aEditorBase
, aTextNode
, offset
,
58 already_AddRefed
<DeleteTextTransaction
>
59 DeleteTextTransaction::MaybeCreateForNextCharacter(EditorBase
& aEditorBase
,
63 aTextNode
.GetData(data
);
64 if (NS_WARN_IF(aOffset
>= data
.Length()) || NS_WARN_IF(data
.IsEmpty())) {
69 if (aOffset
+ 1 < data
.Length() &&
70 NS_IS_SURROGATE_PAIR(data
[aOffset
], data
[aOffset
+ 1])) {
73 return DeleteTextTransaction::MaybeCreate(aEditorBase
, aTextNode
, aOffset
,
77 DeleteTextTransaction::DeleteTextTransaction(EditorBase
& aEditorBase
,
78 Text
& aTextNode
, uint32_t aOffset
,
79 uint32_t aLengthToDelete
)
80 : mEditorBase(&aEditorBase
),
81 mTextNode(&aTextNode
),
83 mLengthToDelete(aLengthToDelete
) {
84 NS_ASSERTION(mTextNode
->Length() >= aOffset
+ aLengthToDelete
,
85 "Trying to delete more characters than in node");
88 std::ostream
& operator<<(std::ostream
& aStream
,
89 const DeleteTextTransaction
& aTransaction
) {
90 aStream
<< "{ mTextNode=" << aTransaction
.mTextNode
.get();
91 if (aTransaction
.mTextNode
) {
92 aStream
<< " (" << *aTransaction
.mTextNode
<< ")";
94 aStream
<< ", mOffset=" << aTransaction
.mOffset
95 << ", mLengthToDelete=" << aTransaction
.mLengthToDelete
96 << ", mDeletedText=\""
97 << NS_ConvertUTF16toUTF8(aTransaction
.mDeletedText
).get() << "\""
98 << ", mEditorBase=" << aTransaction
.mEditorBase
.get() << " }";
102 NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteTextTransaction
, EditTransactionBase
,
103 mEditorBase
, mTextNode
)
105 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteTextTransaction
)
106 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase
)
108 bool DeleteTextTransaction::CanDoIt() const {
109 if (NS_WARN_IF(!mTextNode
) || NS_WARN_IF(!mEditorBase
)) {
112 return mEditorBase
->IsTextEditor() ||
113 HTMLEditUtils::IsSimplyEditableNode(*mTextNode
);
116 NS_IMETHODIMP
DeleteTextTransaction::DoTransaction() {
117 MOZ_LOG(GetLogModule(), LogLevel::Info
,
118 ("%p DeleteTextTransaction::%s this=%s", this, __FUNCTION__
,
119 ToString(*this).c_str()));
121 if (NS_WARN_IF(!CanDoIt())) {
122 return NS_ERROR_NOT_AVAILABLE
;
125 // Get the text that we're about to delete
127 mTextNode
->SubstringData(mOffset
, mLengthToDelete
, mDeletedText
, error
);
128 if (error
.Failed()) {
129 NS_WARNING("Text::SubstringData() failed");
130 return error
.StealNSResult();
133 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
134 OwningNonNull
<Text
> textNode
= *mTextNode
;
135 editorBase
->DoDeleteText(textNode
, mOffset
, mLengthToDelete
, error
);
136 if (error
.Failed()) {
137 NS_WARNING("EditorBase::DoDeleteText() failed");
138 return error
.StealNSResult();
141 editorBase
->RangeUpdaterRef().SelAdjDeleteText(textNode
, mOffset
,
144 if (!editorBase
->AllowsTransactionsToChangeSelection()) {
148 RefPtr
<Selection
> selection
= editorBase
->GetSelection();
149 if (NS_WARN_IF(!selection
)) {
150 return NS_ERROR_FAILURE
;
152 selection
->CollapseInLimiter(EditorRawDOMPoint(textNode
, mOffset
), error
);
153 NS_WARNING_ASSERTION(!error
.Failed(),
154 "Selection::CollapseInLimiter() failed");
155 return error
.StealNSResult();
158 // XXX: We may want to store the selection state and restore it properly. Was
159 // it an insertion point or an extended selection?
160 NS_IMETHODIMP
DeleteTextTransaction::UndoTransaction() {
161 MOZ_LOG(GetLogModule(), LogLevel::Info
,
162 ("%p DeleteTextTransaction::%s this=%s", this, __FUNCTION__
,
163 ToString(*this).c_str()));
165 if (NS_WARN_IF(!CanDoIt())) {
166 return NS_ERROR_NOT_AVAILABLE
;
168 RefPtr
<EditorBase
> editorBase
= mEditorBase
;
169 RefPtr
<Text
> textNode
= mTextNode
;
171 editorBase
->DoInsertText(*textNode
, mOffset
, mDeletedText
, error
);
172 NS_WARNING_ASSERTION(!error
.Failed(), "EditorBase::DoInsertText() failed");
173 return error
.StealNSResult();
176 NS_IMETHODIMP
DeleteTextTransaction::RedoTransaction() {
177 MOZ_LOG(GetLogModule(), LogLevel::Info
,
178 ("%p DeleteTextTransaction::%s this=%s", this, __FUNCTION__
,
179 ToString(*this).c_str()));
180 return DoTransaction();
183 } // namespace mozilla