/src/mozilla-central/editor/libeditor/DeleteTextTransaction.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
5 | | |
6 | | #include "DeleteTextTransaction.h" |
7 | | |
8 | | #include "mozilla/Assertions.h" |
9 | | #include "mozilla/EditorBase.h" |
10 | | #include "mozilla/EditorDOMPoint.h" |
11 | | #include "mozilla/SelectionState.h" |
12 | | #include "mozilla/dom/Selection.h" |
13 | | #include "nsDebug.h" |
14 | | #include "nsError.h" |
15 | | #include "nsIEditor.h" |
16 | | #include "nsISupportsImpl.h" |
17 | | #include "nsAString.h" |
18 | | |
19 | | namespace mozilla { |
20 | | |
21 | | using namespace dom; |
22 | | |
23 | | // static |
24 | | already_AddRefed<DeleteTextTransaction> |
25 | | DeleteTextTransaction::MaybeCreate(EditorBase& aEditorBase, |
26 | | CharacterData& aCharData, |
27 | | uint32_t aOffset, |
28 | | uint32_t aLengthToDelete) |
29 | 0 | { |
30 | 0 | RefPtr<DeleteTextTransaction> transaction = |
31 | 0 | new DeleteTextTransaction(aEditorBase, aCharData, aOffset, aLengthToDelete); |
32 | 0 | return transaction.forget(); |
33 | 0 | } |
34 | | |
35 | | // static |
36 | | already_AddRefed<DeleteTextTransaction> |
37 | | DeleteTextTransaction::MaybeCreateForPreviousCharacter( |
38 | | EditorBase& aEditorBase, |
39 | | CharacterData& aCharData, |
40 | | uint32_t aOffset) |
41 | 0 | { |
42 | 0 | if (NS_WARN_IF(!aOffset)) { |
43 | 0 | return nullptr; |
44 | 0 | } |
45 | 0 | |
46 | 0 | nsAutoString data; |
47 | 0 | aCharData.GetData(data); |
48 | 0 | if (NS_WARN_IF(data.IsEmpty())) { |
49 | 0 | return nullptr; |
50 | 0 | } |
51 | 0 | |
52 | 0 | uint32_t length = 1; |
53 | 0 | uint32_t offset = aOffset - 1; |
54 | 0 | if (offset && |
55 | 0 | NS_IS_LOW_SURROGATE(data[offset]) && |
56 | 0 | NS_IS_HIGH_SURROGATE(data[offset - 1])) { |
57 | 0 | ++length; |
58 | 0 | --offset; |
59 | 0 | } |
60 | 0 | return DeleteTextTransaction::MaybeCreate(aEditorBase, aCharData, |
61 | 0 | offset, length); |
62 | 0 | } |
63 | | |
64 | | // static |
65 | | already_AddRefed<DeleteTextTransaction> |
66 | | DeleteTextTransaction::MaybeCreateForNextCharacter( |
67 | | EditorBase& aEditorBase, |
68 | | CharacterData& aCharData, |
69 | | uint32_t aOffset) |
70 | 0 | { |
71 | 0 | nsAutoString data; |
72 | 0 | aCharData.GetData(data); |
73 | 0 | if (NS_WARN_IF(aOffset >= data.Length()) || |
74 | 0 | NS_WARN_IF(data.IsEmpty())) { |
75 | 0 | return nullptr; |
76 | 0 | } |
77 | 0 | |
78 | 0 | uint32_t length = 1; |
79 | 0 | if (aOffset + 1 < data.Length() && |
80 | 0 | NS_IS_HIGH_SURROGATE(data[aOffset]) && |
81 | 0 | NS_IS_LOW_SURROGATE(data[aOffset + 1])) { |
82 | 0 | ++length; |
83 | 0 | } |
84 | 0 | return DeleteTextTransaction::MaybeCreate(aEditorBase, aCharData, |
85 | 0 | aOffset, length); |
86 | 0 | } |
87 | | |
88 | | DeleteTextTransaction::DeleteTextTransaction( |
89 | | EditorBase& aEditorBase, |
90 | | CharacterData& aCharData, |
91 | | uint32_t aOffset, |
92 | | uint32_t aLengthToDelete) |
93 | | : mEditorBase(&aEditorBase) |
94 | | , mCharData(&aCharData) |
95 | | , mOffset(aOffset) |
96 | | , mLengthToDelete(aLengthToDelete) |
97 | 0 | { |
98 | 0 | NS_ASSERTION(mCharData->Length() >= aOffset + aLengthToDelete, |
99 | 0 | "Trying to delete more characters than in node"); |
100 | 0 | } |
101 | | |
102 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteTextTransaction, EditTransactionBase, |
103 | | mEditorBase, |
104 | | mCharData) |
105 | | |
106 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteTextTransaction) |
107 | 0 | NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase) |
108 | | |
109 | | bool |
110 | | DeleteTextTransaction::CanDoIt() const |
111 | 0 | { |
112 | 0 | if (NS_WARN_IF(!mCharData) || NS_WARN_IF(!mEditorBase)) { |
113 | 0 | return false; |
114 | 0 | } |
115 | 0 | return mEditorBase->IsModifiableNode(*mCharData); |
116 | 0 | } |
117 | | |
118 | | NS_IMETHODIMP |
119 | | DeleteTextTransaction::DoTransaction() |
120 | 0 | { |
121 | 0 | if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mCharData)) { |
122 | 0 | return NS_ERROR_NOT_AVAILABLE; |
123 | 0 | } |
124 | 0 | |
125 | 0 | // Get the text that we're about to delete |
126 | 0 | ErrorResult err; |
127 | 0 | mCharData->SubstringData(mOffset, mLengthToDelete, mDeletedText, err); |
128 | 0 | if (NS_WARN_IF(err.Failed())) { |
129 | 0 | return err.StealNSResult(); |
130 | 0 | } |
131 | 0 | |
132 | 0 | mCharData->DeleteData(mOffset, mLengthToDelete, err); |
133 | 0 | if (NS_WARN_IF(err.Failed())) { |
134 | 0 | return err.StealNSResult(); |
135 | 0 | } |
136 | 0 | |
137 | 0 | mEditorBase->RangeUpdaterRef(). |
138 | 0 | SelAdjDeleteText(mCharData, mOffset, mLengthToDelete); |
139 | 0 |
|
140 | 0 | if (!mEditorBase->AllowsTransactionsToChangeSelection()) { |
141 | 0 | return NS_OK; |
142 | 0 | } |
143 | 0 | |
144 | 0 | RefPtr<Selection> selection = mEditorBase->GetSelection(); |
145 | 0 | if (NS_WARN_IF(!selection)) { |
146 | 0 | return NS_ERROR_FAILURE; |
147 | 0 | } |
148 | 0 | ErrorResult error; |
149 | 0 | selection->Collapse(EditorRawDOMPoint(mCharData, mOffset), error); |
150 | 0 | if (NS_WARN_IF(error.Failed())) { |
151 | 0 | return error.StealNSResult(); |
152 | 0 | } |
153 | 0 | return NS_OK; |
154 | 0 | } |
155 | | |
156 | | //XXX: We may want to store the selection state and restore it properly. Was |
157 | | // it an insertion point or an extended selection? |
158 | | NS_IMETHODIMP |
159 | | DeleteTextTransaction::UndoTransaction() |
160 | 0 | { |
161 | 0 | if (NS_WARN_IF(!mCharData)) { |
162 | 0 | return NS_ERROR_NOT_INITIALIZED; |
163 | 0 | } |
164 | 0 | ErrorResult rv; |
165 | 0 | mCharData->InsertData(mOffset, mDeletedText, rv); |
166 | 0 | return rv.StealNSResult(); |
167 | 0 | } |
168 | | |
169 | | } // namespace mozilla |