Bug 1769033 - Add OpenBSD sandboxing support r=gaston
[gecko.git] / editor / libeditor / InsertNodeTransaction.cpp
blobf95d84262ed604349dfe72a264dda456439a24f3
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 "InsertNodeTransaction.h"
8 #include "EditorBase.h" // for EditorBase
9 #include "EditorDOMPoint.h" // for EditorDOMPoint
10 #include "HTMLEditor.h" // for HTMLEditor
11 #include "TextEditor.h" // for TextEditor
13 #include "mozilla/Logging.h"
14 #include "mozilla/ToString.h"
16 #include "nsAString.h"
17 #include "nsDebug.h" // for NS_WARNING, etc.
18 #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc.
19 #include "nsIContent.h" // for nsIContent
20 #include "nsMemory.h" // for nsMemory
21 #include "nsReadableUtils.h" // for ToNewCString
22 #include "nsString.h" // for nsString
24 namespace mozilla {
26 using namespace dom;
28 template already_AddRefed<InsertNodeTransaction> InsertNodeTransaction::Create(
29 EditorBase& aEditorBase, nsIContent& aContentToInsert,
30 const EditorDOMPoint& aPointToInsert);
31 template already_AddRefed<InsertNodeTransaction> InsertNodeTransaction::Create(
32 EditorBase& aEditorBase, nsIContent& aContentToInsert,
33 const EditorRawDOMPoint& aPointToInsert);
35 // static
36 template <typename PT, typename CT>
37 already_AddRefed<InsertNodeTransaction> InsertNodeTransaction::Create(
38 EditorBase& aEditorBase, nsIContent& aContentToInsert,
39 const EditorDOMPointBase<PT, CT>& aPointToInsert) {
40 RefPtr<InsertNodeTransaction> transaction =
41 new InsertNodeTransaction(aEditorBase, aContentToInsert, aPointToInsert);
42 return transaction.forget();
45 template <typename PT, typename CT>
46 InsertNodeTransaction::InsertNodeTransaction(
47 EditorBase& aEditorBase, nsIContent& aContentToInsert,
48 const EditorDOMPointBase<PT, CT>& aPointToInsert)
49 : mContentToInsert(&aContentToInsert),
50 mPointToInsert(aPointToInsert.template To<EditorDOMPoint>()),
51 mEditorBase(&aEditorBase) {
52 MOZ_ASSERT(mPointToInsert.IsSetAndValid());
53 // Ensure mPointToInsert stores child at offset.
54 Unused << mPointToInsert.GetChild();
57 std::ostream& operator<<(std::ostream& aStream,
58 const InsertNodeTransaction& aTransaction) {
59 aStream << "{ mContentToInsert=" << aTransaction.mContentToInsert.get();
60 if (aTransaction.mContentToInsert) {
61 if (aTransaction.mContentToInsert->IsText()) {
62 nsAutoString data;
63 aTransaction.mContentToInsert->AsText()->GetData(data);
64 aStream << " (#text \"" << NS_ConvertUTF16toUTF8(data).get() << "\")";
65 } else {
66 aStream << " (" << *aTransaction.mContentToInsert << ")";
69 aStream << ", mPointToInsert=" << aTransaction.mPointToInsert
70 << ", mEditorBase=" << aTransaction.mEditorBase.get() << " }";
71 return aStream;
74 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertNodeTransaction, EditTransactionBase,
75 mEditorBase, mContentToInsert,
76 mPointToInsert)
78 NS_IMPL_ADDREF_INHERITED(InsertNodeTransaction, EditTransactionBase)
79 NS_IMPL_RELEASE_INHERITED(InsertNodeTransaction, EditTransactionBase)
80 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertNodeTransaction)
81 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
83 NS_IMETHODIMP InsertNodeTransaction::DoTransaction() {
84 MOZ_LOG(GetLogModule(), LogLevel::Info,
85 ("%p InsertNodeTransaction::%s this=%s", this, __FUNCTION__,
86 ToString(*this).c_str()));
88 if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mContentToInsert) ||
89 NS_WARN_IF(!mPointToInsert.IsSet())) {
90 return NS_ERROR_NOT_AVAILABLE;
93 MOZ_ASSERT_IF(mEditorBase->IsTextEditor(), !mContentToInsert->IsText());
95 if (!mPointToInsert.IsSetAndValid()) {
96 // It seems that DOM tree has been changed after first DoTransaction()
97 // and current RedoTranaction() call.
98 if (mPointToInsert.GetChild()) {
99 EditorDOMPoint newPointToInsert(mPointToInsert.GetChild());
100 if (!newPointToInsert.IsSet()) {
101 // The insertion point has been removed from the DOM tree.
102 // In this case, we should append the node to the container instead.
103 newPointToInsert.SetToEndOf(mPointToInsert.GetContainer());
104 if (NS_WARN_IF(!newPointToInsert.IsSet())) {
105 return NS_ERROR_FAILURE;
108 mPointToInsert = newPointToInsert;
109 } else {
110 mPointToInsert.SetToEndOf(mPointToInsert.GetContainer());
111 if (NS_WARN_IF(!mPointToInsert.IsSet())) {
112 return NS_ERROR_FAILURE;
117 OwningNonNull<EditorBase> editorBase = *mEditorBase;
118 OwningNonNull<nsIContent> contentToInsert = *mContentToInsert;
119 OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
120 nsCOMPtr<nsIContent> refChild = mPointToInsert.GetChild();
121 if (contentToInsert->IsElement()) {
122 nsresult rv = editorBase->MarkElementDirty(
123 MOZ_KnownLive(*contentToInsert->AsElement()));
124 if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
125 return EditorBase::ToGenericNSResult(rv);
127 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
128 "EditorBase::MarkElementDirty() failed, but ignored");
131 IgnoredErrorResult error;
132 container->InsertBefore(contentToInsert, refChild, error);
133 // InsertBefore() may call MightThrowJSException() even if there is no
134 // error. We don't need the flag here.
135 error.WouldReportJSException();
136 if (error.Failed()) {
137 NS_WARNING("nsINode::InsertBefore() failed");
138 return error.StealNSResult();
141 return NS_OK;
144 NS_IMETHODIMP InsertNodeTransaction::UndoTransaction() {
145 MOZ_LOG(GetLogModule(), LogLevel::Info,
146 ("%p InsertNodeTransaction::%s this=%s", this, __FUNCTION__,
147 ToString(*this).c_str()));
149 if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mContentToInsert) ||
150 NS_WARN_IF(!mPointToInsert.IsSet())) {
151 return NS_ERROR_NOT_INITIALIZED;
153 // XXX If the inserted node has been moved to different container node or
154 // just removed from the DOM tree, this always fails.
155 OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
156 OwningNonNull<nsIContent> contentToInsert = *mContentToInsert;
157 ErrorResult error;
158 container->RemoveChild(contentToInsert, error);
159 NS_WARNING_ASSERTION(!error.Failed(), "nsINode::RemoveChild() failed");
160 return error.StealNSResult();
163 NS_IMETHODIMP InsertNodeTransaction::RedoTransaction() {
164 MOZ_LOG(GetLogModule(), LogLevel::Info,
165 ("%p InsertNodeTransaction::%s this=%s", this, __FUNCTION__,
166 ToString(*this).c_str()));
167 nsresult rv = DoTransaction();
168 if (MOZ_UNLIKELY(NS_FAILED(rv))) {
169 NS_WARNING("InsertNodeTransaction::RedoTransaction() failed");
170 return rv;
173 if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
174 return NS_OK;
177 OwningNonNull<EditorBase> editorBase(*mEditorBase);
178 rv = editorBase->CollapseSelectionTo(
179 SuggestPointToPutCaret<EditorRawDOMPoint>());
180 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
181 "EditorBase::CollapseSelectionTo() failed, but ignored");
182 return NS_OK;
185 } // namespace mozilla