Bug 1772588 [wpt PR 34302] - [wpt] Add test for block-in-inline offsetParent., a...
[gecko.git] / editor / libeditor / InsertTextTransaction.cpp
blobc92ed0c51d99b8e813c160442f2042fa8748d745
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 "InsertTextTransaction.h"
8 #include "mozilla/EditorBase.h" // mEditorBase
9 #include "mozilla/Logging.h"
10 #include "mozilla/SelectionState.h" // RangeUpdater
11 #include "mozilla/ToString.h"
12 #include "mozilla/dom/Selection.h" // Selection local var
13 #include "mozilla/dom/Text.h" // mTextNode
14 #include "nsAString.h" // nsAString parameter
15 #include "nsDebug.h" // for NS_ASSERTION, etc.
16 #include "nsError.h" // for NS_OK, etc.
17 #include "nsQueryObject.h" // for do_QueryObject
19 namespace mozilla {
21 using namespace dom;
23 // static
24 already_AddRefed<InsertTextTransaction> InsertTextTransaction::Create(
25 EditorBase& aEditorBase, const nsAString& aStringToInsert,
26 const EditorDOMPointInText& aPointToInsert) {
27 MOZ_ASSERT(aPointToInsert.IsSetAndValid());
28 RefPtr<InsertTextTransaction> transaction =
29 new InsertTextTransaction(aEditorBase, aStringToInsert, aPointToInsert);
30 return transaction.forget();
33 InsertTextTransaction::InsertTextTransaction(
34 EditorBase& aEditorBase, const nsAString& aStringToInsert,
35 const EditorDOMPointInText& aPointToInsert)
36 : mTextNode(aPointToInsert.ContainerAsText()),
37 mOffset(aPointToInsert.Offset()),
38 mStringToInsert(aStringToInsert),
39 mEditorBase(&aEditorBase) {}
41 std::ostream& operator<<(std::ostream& aStream,
42 const InsertTextTransaction& aTransaction) {
43 aStream << "{ mTextNode=" << aTransaction.mTextNode.get();
44 if (aTransaction.mTextNode) {
45 aStream << " (" << *aTransaction.mTextNode << ")";
47 aStream << ", mOffset=" << aTransaction.mOffset << ", mStringToInsert=\""
48 << NS_ConvertUTF16toUTF8(aTransaction.mStringToInsert).get() << "\""
49 << ", mEditorBase=" << aTransaction.mEditorBase.get() << " }";
50 return aStream;
53 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase,
54 mEditorBase, mTextNode)
56 NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase)
57 NS_IMPL_RELEASE_INHERITED(InsertTextTransaction, EditTransactionBase)
58 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTransaction)
59 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
61 NS_IMETHODIMP InsertTextTransaction::DoTransaction() {
62 MOZ_LOG(GetLogModule(), LogLevel::Info,
63 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__,
64 ToString(*this).c_str()));
66 if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
67 return NS_ERROR_NOT_AVAILABLE;
70 OwningNonNull<EditorBase> editorBase = *mEditorBase;
71 OwningNonNull<Text> textNode = *mTextNode;
73 ErrorResult error;
74 editorBase->DoInsertText(textNode, mOffset, mStringToInsert, error);
75 if (error.Failed()) {
76 NS_WARNING("EditorBase::DoInsertText() failed");
77 return error.StealNSResult();
80 // Only set selection to insertion point if editor gives permission
81 if (editorBase->AllowsTransactionsToChangeSelection()) {
82 RefPtr<Selection> selection = editorBase->GetSelection();
83 if (NS_WARN_IF(!selection)) {
84 return NS_ERROR_FAILURE;
86 DebugOnly<nsresult> rvIgnored = editorBase->CollapseSelectionTo(
87 EditorRawDOMPoint(textNode, mOffset + mStringToInsert.Length()));
88 NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
89 "EditorBase::CollapseSelectionTo() failed, but ignored");
90 // Keep handling to adjust the ranges in the range updater even if the
91 // editor is destroyed.
92 } else {
93 // Do nothing - DOM Range gravity will adjust selection
95 // XXX Other transactions do not do this but its callers do.
96 // Why do this transaction do this by itself?
97 editorBase->RangeUpdaterRef().SelAdjInsertText(textNode, mOffset,
98 mStringToInsert.Length());
100 return MOZ_UNLIKELY(editorBase->Destroyed()) ? NS_ERROR_EDITOR_DESTROYED
101 : NS_OK;
104 NS_IMETHODIMP InsertTextTransaction::UndoTransaction() {
105 MOZ_LOG(GetLogModule(), LogLevel::Info,
106 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__,
107 ToString(*this).c_str()));
109 if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
110 return NS_ERROR_NOT_INITIALIZED;
112 OwningNonNull<EditorBase> editorBase = *mEditorBase;
113 OwningNonNull<Text> textNode = *mTextNode;
114 ErrorResult error;
115 editorBase->DoDeleteText(textNode, mOffset, mStringToInsert.Length(), error);
116 NS_WARNING_ASSERTION(!error.Failed(), "EditorBase::DoDeleteText() failed");
117 return error.StealNSResult();
120 NS_IMETHODIMP InsertTextTransaction::RedoTransaction() {
121 MOZ_LOG(GetLogModule(), LogLevel::Info,
122 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__,
123 ToString(*this).c_str()));
124 return DoTransaction();
127 NS_IMETHODIMP InsertTextTransaction::Merge(nsITransaction* aOtherTransaction,
128 bool* aDidMerge) {
129 MOZ_LOG(GetLogModule(), LogLevel::Debug,
130 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) this=%s", this,
131 __FUNCTION__, aOtherTransaction, ToString(*this).c_str()));
133 if (NS_WARN_IF(!aOtherTransaction) || NS_WARN_IF(!aDidMerge)) {
134 return NS_ERROR_INVALID_ARG;
136 // Set out param default value
137 *aDidMerge = false;
139 RefPtr<EditTransactionBase> otherTransactionBase =
140 aOtherTransaction->GetAsEditTransactionBase();
141 if (!otherTransactionBase) {
142 MOZ_LOG(
143 GetLogModule(), LogLevel::Debug,
144 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
145 this, __FUNCTION__, aOtherTransaction));
146 return NS_OK;
149 // If aTransaction is a InsertTextTransaction, and if the selection hasn't
150 // changed, then absorb it.
151 InsertTextTransaction* otherInsertTextTransaction =
152 otherTransactionBase->GetAsInsertTextTransaction();
153 if (!otherInsertTextTransaction ||
154 !IsSequentialInsert(*otherInsertTextTransaction)) {
155 MOZ_LOG(
156 GetLogModule(), LogLevel::Debug,
157 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
158 this, __FUNCTION__, aOtherTransaction));
159 return NS_OK;
162 nsAutoString otherData;
163 otherInsertTextTransaction->GetData(otherData);
164 mStringToInsert += otherData;
165 *aDidMerge = true;
166 MOZ_LOG(GetLogModule(), LogLevel::Debug,
167 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned true",
168 this, __FUNCTION__, aOtherTransaction));
169 return NS_OK;
172 /* ============ private methods ================== */
174 void InsertTextTransaction::GetData(nsString& aResult) {
175 aResult = mStringToInsert;
178 bool InsertTextTransaction::IsSequentialInsert(
179 InsertTextTransaction& aOtherTransaction) {
180 return aOtherTransaction.mTextNode == mTextNode &&
181 aOtherTransaction.mOffset == mOffset + mStringToInsert.Length();
184 } // namespace mozilla