Bug 1814798 - pt 1. Add bool to enable/disable PHC at runtime r=glandium
[gecko.git] / editor / libeditor / JoinNodesTransaction.cpp
blob15891938c85471f7e7b40171c4ab99e284f00d4b
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 "JoinNodesTransaction.h"
8 #include "EditorDOMPoint.h" // for EditorDOMPoint, etc.
9 #include "HTMLEditHelpers.h" // for SplitNodeResult
10 #include "JoinSplitNodeDirection.h" // JoinNodesDirection
11 #include "HTMLEditor.h" // for HTMLEditor
12 #include "HTMLEditorInlines.h"
13 #include "HTMLEditUtils.h"
15 #include "mozilla/Logging.h"
16 #include "mozilla/ToString.h"
17 #include "mozilla/dom/Text.h"
19 #include "nsAString.h"
20 #include "nsDebug.h" // for NS_ASSERTION, etc.
21 #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc.
22 #include "nsIContent.h" // for nsIContent
23 #include "nsISupportsImpl.h" // for QueryInterface, etc.
25 namespace mozilla {
27 using namespace dom;
29 // static
30 already_AddRefed<JoinNodesTransaction> JoinNodesTransaction::MaybeCreate(
31 HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
32 nsIContent& aRightContent) {
33 RefPtr<JoinNodesTransaction> transaction =
34 new JoinNodesTransaction(aHTMLEditor, aLeftContent, aRightContent);
35 if (NS_WARN_IF(!transaction->CanDoIt())) {
36 return nullptr;
38 return transaction.forget();
41 JoinNodesTransaction::JoinNodesTransaction(HTMLEditor& aHTMLEditor,
42 nsIContent& aLeftContent,
43 nsIContent& aRightContent)
44 : mHTMLEditor(&aHTMLEditor),
45 mRemovedContent(aHTMLEditor.GetJoinNodesDirection() ==
46 JoinNodesDirection::LeftNodeIntoRightNode
47 ? &aLeftContent
48 : &aRightContent),
49 mKeepingContent(aHTMLEditor.GetJoinNodesDirection() ==
50 JoinNodesDirection::LeftNodeIntoRightNode
51 ? &aRightContent
52 : &aLeftContent) {
53 // printf("JoinNodesTransaction size: %zu\n", sizeof(JoinNodesTransaction));
54 static_assert(sizeof(JoinNodesTransaction) <= 64,
55 "Transaction classes may be created a lot and may be alive "
56 "long so that keep the foot print smaller as far as possible");
59 std::ostream& operator<<(std::ostream& aStream,
60 const JoinNodesTransaction& aTransaction) {
61 aStream << "{ mParentNode=" << aTransaction.mParentNode.get();
62 if (aTransaction.mParentNode) {
63 aStream << " (" << *aTransaction.mParentNode << ")";
65 aStream << ", mRemovedContent=" << aTransaction.mRemovedContent.get();
66 if (aTransaction.mRemovedContent) {
67 aStream << " (" << *aTransaction.mRemovedContent << ")";
69 aStream << ", mKeepingContent=" << aTransaction.mKeepingContent.get();
70 if (aTransaction.mKeepingContent) {
71 aStream << " (" << *aTransaction.mKeepingContent << ")";
73 aStream << ", mJoinedOffset=" << aTransaction.mJoinedOffset
74 << ", mHTMLEditor=" << aTransaction.mHTMLEditor.get()
75 << ", GetJoinNodesDirection()="
76 << aTransaction.GetJoinNodesDirection() << " }";
77 return aStream;
80 NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodesTransaction, EditTransactionBase,
81 mHTMLEditor, mParentNode, mRemovedContent,
82 mKeepingContent)
84 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinNodesTransaction)
85 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
87 SplitNodeDirection JoinNodesTransaction::GetSplitNodeDirection() const {
88 return MOZ_LIKELY(mHTMLEditor) ? mHTMLEditor->GetSplitNodeDirection()
89 : SplitNodeDirection::LeftNodeIsNewOne;
92 JoinNodesDirection JoinNodesTransaction::GetJoinNodesDirection() const {
93 return MOZ_LIKELY(mHTMLEditor) ? mHTMLEditor->GetJoinNodesDirection()
94 : JoinNodesDirection::LeftNodeIntoRightNode;
97 bool JoinNodesTransaction::CanDoIt() const {
98 if (NS_WARN_IF(!mKeepingContent) || NS_WARN_IF(!mRemovedContent) ||
99 NS_WARN_IF(!mHTMLEditor) ||
100 NS_WARN_IF(mRemovedContent->IsBeingRemoved()) ||
101 !mKeepingContent->IsInComposedDoc()) {
102 return false;
104 return HTMLEditUtils::IsRemovableFromParentNode(*mRemovedContent);
107 // After DoTransaction() and RedoTransaction(), the left node is removed from
108 // the content tree and right node remains.
109 NS_IMETHODIMP JoinNodesTransaction::DoTransaction() {
110 MOZ_LOG(GetLogModule(), LogLevel::Info,
111 ("%p JoinNodesTransaction::%s this=%s", this, __FUNCTION__,
112 ToString(*this).c_str()));
114 return DoTransactionInternal(RedoingTransaction::No);
117 nsresult JoinNodesTransaction::DoTransactionInternal(
118 RedoingTransaction aRedoingTransaction) {
119 if (MOZ_UNLIKELY(NS_WARN_IF(!mHTMLEditor) || NS_WARN_IF(!mKeepingContent) ||
120 NS_WARN_IF(!mRemovedContent) ||
121 NS_WARN_IF(mRemovedContent->IsBeingRemoved()))) {
122 return NS_ERROR_NOT_AVAILABLE;
125 nsINode* removingContentParentNode = mRemovedContent->GetParentNode();
126 if (MOZ_UNLIKELY(NS_WARN_IF(!removingContentParentNode))) {
127 return NS_ERROR_NOT_AVAILABLE;
130 // Verify that the joining content nodes have the same parent
131 if (MOZ_UNLIKELY(removingContentParentNode !=
132 mKeepingContent->GetParentNode())) {
133 NS_ASSERTION(false, "Nodes do not have same parent");
134 return NS_ERROR_NOT_AVAILABLE;
137 // Set this instance's mParentNode. Other methods will see a non-null
138 // mParentNode and know all is well
139 mParentNode = removingContentParentNode;
140 // For now, setting mJoinedOffset to removed content length so that
141 // CreateJoinedPoint returns a point in mKeepingContent whose offset is
142 // the result if all content in mRemovedContent are moved to start or end of
143 // mKeepingContent without any intervation. The offset will be adjusted
144 // below.
145 mJoinedOffset =
146 GetJoinNodesDirection() == JoinNodesDirection::LeftNodeIntoRightNode
147 ? mRemovedContent->Length()
148 : mKeepingContent->Length();
150 const OwningNonNull<HTMLEditor> htmlEditor = *mHTMLEditor;
151 const OwningNonNull<nsIContent> removingContent = *mRemovedContent;
152 const OwningNonNull<nsIContent> keepingContent = *mKeepingContent;
153 nsresult rv;
154 // Let's try to get actual joined point with the tacker.
155 EditorDOMPoint joinNodesPoint =
156 GetJoinNodesDirection() == JoinNodesDirection::LeftNodeIntoRightNode
157 ? EditorDOMPoint(keepingContent, 0u)
158 : EditorDOMPoint::AtEndOf(keepingContent);
160 AutoTrackDOMPoint trackJoinNodePoint(htmlEditor->RangeUpdaterRef(),
161 &joinNodesPoint);
162 rv = htmlEditor->DoJoinNodes(keepingContent, removingContent,
163 GetJoinNodesDirection());
164 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::DoJoinNodes() failed");
166 // Adjust join node offset to the actual offset where the original first
167 // content of the right node is.
168 mJoinedOffset = joinNodesPoint.Offset();
170 if (aRedoingTransaction == RedoingTransaction::No) {
171 htmlEditor->DidJoinNodesTransaction(*this, rv);
174 return rv;
177 // XXX: What if instead of split, we just deleted the unneeded children of
178 // mRight and re-inserted mLeft?
179 NS_IMETHODIMP JoinNodesTransaction::UndoTransaction() {
180 MOZ_LOG(GetLogModule(), LogLevel::Info,
181 ("%p JoinNodesTransaction::%s this=%s", this, __FUNCTION__,
182 ToString(*this).c_str()));
184 if (NS_WARN_IF(!mParentNode) || NS_WARN_IF(!mKeepingContent) ||
185 NS_WARN_IF(!mRemovedContent) || NS_WARN_IF(!mHTMLEditor)) {
186 return NS_ERROR_NOT_AVAILABLE;
189 const OwningNonNull<HTMLEditor> htmlEditor = *mHTMLEditor;
190 const OwningNonNull<nsIContent> removedContent = *mRemovedContent;
192 Result<SplitNodeResult, nsresult> splitNodeResult =
193 htmlEditor->DoSplitNode(CreateJoinedPoint<EditorDOMPoint>(),
194 removedContent, GetSplitNodeDirection());
195 if (MOZ_UNLIKELY(splitNodeResult.isErr())) {
196 NS_WARNING("HTMLEditor::DoSplitNode() failed");
197 return splitNodeResult.unwrapErr();
199 // When adding caret suggestion to SplitNodeResult, here didn't change
200 // selection so that just ignore it.
201 splitNodeResult.inspect().IgnoreCaretPointSuggestion();
202 return NS_OK;
205 NS_IMETHODIMP JoinNodesTransaction::RedoTransaction() {
206 MOZ_LOG(GetLogModule(), LogLevel::Info,
207 ("%p JoinNodesTransaction::%s this=%s", this, __FUNCTION__,
208 ToString(*this).c_str()));
209 return DoTransactionInternal(RedoingTransaction::Yes);
212 } // namespace mozilla