summaryrefslogtreecommitdiffstats
path: root/editor/libeditor/PlaceholderTransaction.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /editor/libeditor/PlaceholderTransaction.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'editor/libeditor/PlaceholderTransaction.cpp')
-rw-r--r--editor/libeditor/PlaceholderTransaction.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/editor/libeditor/PlaceholderTransaction.cpp b/editor/libeditor/PlaceholderTransaction.cpp
new file mode 100644
index 0000000000..1f616dee98
--- /dev/null
+++ b/editor/libeditor/PlaceholderTransaction.cpp
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PlaceholderTransaction.h"
+
+#include <utility>
+
+#include "CompositionTransaction.h"
+#include "mozilla/EditorBase.h"
+#include "mozilla/dom/Selection.h"
+#include "nsGkAtoms.h"
+#include "nsQueryObject.h"
+
+namespace mozilla {
+
+using namespace dom;
+
+PlaceholderTransaction::PlaceholderTransaction(
+ EditorBase& aEditorBase, nsStaticAtom& aName,
+ Maybe<SelectionState>&& aSelState)
+ : mEditorBase(&aEditorBase),
+ mCompositionTransaction(nullptr),
+ mStartSel(*std::move(aSelState)),
+ mAbsorb(true),
+ mCommitted(false) {
+ mName = &aName;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTransaction)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTransaction,
+ EditAggregateTransaction)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorBase);
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mStartSel);
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTransaction,
+ EditAggregateTransaction)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorBase);
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStartSel);
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTransaction)
+NS_INTERFACE_MAP_END_INHERITING(EditAggregateTransaction)
+
+NS_IMPL_ADDREF_INHERITED(PlaceholderTransaction, EditAggregateTransaction)
+NS_IMPL_RELEASE_INHERITED(PlaceholderTransaction, EditAggregateTransaction)
+
+NS_IMETHODIMP PlaceholderTransaction::DoTransaction() { return NS_OK; }
+
+NS_IMETHODIMP PlaceholderTransaction::UndoTransaction() {
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ // Undo transactions.
+ nsresult rv = EditAggregateTransaction::UndoTransaction();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("EditAggregateTransaction::UndoTransaction() failed");
+ return rv;
+ }
+
+ // now restore selection
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
+ if (NS_WARN_IF(!selection)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = mStartSel.RestoreSelection(*selection);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "SelectionState::RestoreSelection() failed");
+ return rv;
+}
+
+NS_IMETHODIMP PlaceholderTransaction::RedoTransaction() {
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ // Redo transactions.
+ nsresult rv = EditAggregateTransaction::RedoTransaction();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("EditAggregateTransaction::RedoTransaction() failed");
+ return rv;
+ }
+
+ // now restore selection
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
+ if (NS_WARN_IF(!selection)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = mEndSel.RestoreSelection(*selection);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "SelectionState::RestoreSelection() failed");
+ return rv;
+}
+
+NS_IMETHODIMP PlaceholderTransaction::Merge(nsITransaction* aOtherTransaction,
+ bool* aDidMerge) {
+ if (NS_WARN_IF(!aDidMerge) || NS_WARN_IF(!aOtherTransaction)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // set out param default value
+ *aDidMerge = false;
+
+ if (mForwardingTransaction) {
+ MOZ_ASSERT_UNREACHABLE(
+ "tried to merge into a placeholder that was in "
+ "forwarding mode!");
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<EditTransactionBase> otherTransactionBase =
+ aOtherTransaction->GetAsEditTransactionBase();
+ if (!otherTransactionBase) {
+ return NS_OK;
+ }
+
+ // We are absorbing all transactions if mAbsorb is lit.
+ if (mAbsorb) {
+ if (CompositionTransaction* otherCompositionTransaction =
+ otherTransactionBase->GetAsCompositionTransaction()) {
+ // special handling for CompositionTransaction's: they need to merge with
+ // any previous CompositionTransaction in this placeholder, if possible.
+ if (!mCompositionTransaction) {
+ // this is the first IME txn in the placeholder
+ mCompositionTransaction = otherCompositionTransaction;
+ DebugOnly<nsresult> rvIgnored =
+ AppendChild(otherCompositionTransaction);
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rvIgnored),
+ "EditAggregateTransaction::AppendChild() failed, but ignored");
+ } else {
+ bool didMerge;
+ mCompositionTransaction->Merge(otherCompositionTransaction, &didMerge);
+ if (!didMerge) {
+ // it wouldn't merge. Earlier IME txn is already committed and will
+ // not absorb further IME txns. So just stack this one after it
+ // and remember it as a candidate for further merges.
+ mCompositionTransaction = otherCompositionTransaction;
+ DebugOnly<nsresult> rvIgnored =
+ AppendChild(otherCompositionTransaction);
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rvIgnored),
+ "EditAggregateTransaction::AppendChild() failed, but ignored");
+ }
+ }
+ } else {
+ PlaceholderTransaction* otherPlaceholderTransaction =
+ otherTransactionBase->GetAsPlaceholderTransaction();
+ if (!otherPlaceholderTransaction) {
+ // See bug 171243: just drop incoming placeholders on the floor.
+ // Their children will be swallowed by this preexisting one.
+ DebugOnly<nsresult> rvIgnored = AppendChild(otherTransactionBase);
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rvIgnored),
+ "EditAggregateTransaction::AppendChild() failed, but ignored");
+ }
+ }
+ *aDidMerge = true;
+ // RememberEndingSelection();
+ // efficiency hack: no need to remember selection here, as we haven't yet
+ // finished the initial batch and we know we will be told when the batch
+ // ends. we can remeber the selection then.
+ return NS_OK;
+ }
+
+ // merge typing or IME or deletion transactions if the selection matches
+ if (mCommitted ||
+ (mName != nsGkAtoms::TypingTxnName && mName != nsGkAtoms::IMETxnName &&
+ mName != nsGkAtoms::DeleteTxnName)) {
+ return NS_OK;
+ }
+
+ PlaceholderTransaction* otherPlaceholderTransaction =
+ otherTransactionBase->GetAsPlaceholderTransaction();
+ if (!otherPlaceholderTransaction) {
+ return NS_OK;
+ }
+
+ RefPtr<nsAtom> otherTransactionName;
+ DebugOnly<nsresult> rvIgnored = otherPlaceholderTransaction->GetName(
+ getter_AddRefs(otherTransactionName));
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
+ "PlaceholderTransaction::GetName() failed, but ignored");
+ if (!otherTransactionName || otherTransactionName == nsGkAtoms::_empty ||
+ otherTransactionName != mName) {
+ return NS_OK;
+ }
+ // check if start selection of next placeholder matches
+ // end selection of this placeholder
+ if (!otherPlaceholderTransaction->StartSelectionEquals(mEndSel)) {
+ return NS_OK;
+ }
+ mAbsorb = true; // we need to start absorbing again
+ otherPlaceholderTransaction->ForwardEndBatchTo(*this);
+ // AppendChild(editTransactionBase);
+ // see bug 171243: we don't need to merge placeholders
+ // into placeholders. We just reactivate merging in the
+ // pre-existing placeholder and drop the new one on the floor. The
+ // EndPlaceHolderBatch() call on the new placeholder will be
+ // forwarded to this older one.
+ rvIgnored = RememberEndingSelection();
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rvIgnored),
+ "PlaceholderTransaction::RememberEndingSelection() failed, but "
+ "ignored");
+ *aDidMerge = true;
+ return NS_OK;
+}
+
+bool PlaceholderTransaction::StartSelectionEquals(
+ SelectionState& aSelectionState) {
+ // determine if starting selection matches the given selection state.
+ // note that we only care about collapsed selections.
+ return mStartSel.IsCollapsed() && aSelectionState.IsCollapsed() &&
+ mStartSel.Equals(aSelectionState);
+}
+
+nsresult PlaceholderTransaction::EndPlaceHolderBatch() {
+ mAbsorb = false;
+
+ if (mForwardingTransaction) {
+ if (mForwardingTransaction) {
+ DebugOnly<nsresult> rvIgnored =
+ mForwardingTransaction->EndPlaceHolderBatch();
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rvIgnored),
+ "PlaceholderTransaction::EndPlaceHolderBatch() failed, but ignored");
+ }
+ }
+ // remember our selection state.
+ nsresult rv = RememberEndingSelection();
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rv),
+ "PlaceholderTransaction::RememberEndingSelection() failed");
+ return rv;
+}
+
+nsresult PlaceholderTransaction::RememberEndingSelection() {
+ if (NS_WARN_IF(!mEditorBase)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
+ if (NS_WARN_IF(!selection)) {
+ return NS_ERROR_FAILURE;
+ }
+ mEndSel.SaveSelection(*selection);
+ return NS_OK;
+}
+
+} // namespace mozilla