tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

InsertTextTransaction.cpp (8948B)


      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 "InsertTextTransaction.h"
      7 
      8 #include "ErrorList.h"
      9 #include "mozilla/EditorBase.h"  // mEditorBase
     10 #include "mozilla/Logging.h"
     11 #include "mozilla/SelectionState.h"  // RangeUpdater
     12 #include "mozilla/TextEditor.h"      // TextEditor
     13 #include "mozilla/ToString.h"
     14 #include "mozilla/dom/Selection.h"  // Selection local var
     15 #include "mozilla/dom/Text.h"       // mTextNode
     16 
     17 #include "nsAString.h"      // nsAString parameter
     18 #include "nsDebug.h"        // for NS_ASSERTION, etc.
     19 #include "nsError.h"        // for NS_OK, etc.
     20 #include "nsQueryObject.h"  // for do_QueryObject
     21 
     22 namespace mozilla {
     23 
     24 using namespace dom;
     25 
     26 // static
     27 already_AddRefed<InsertTextTransaction> InsertTextTransaction::Create(
     28    EditorBase& aEditorBase, const nsAString& aStringToInsert,
     29    const EditorDOMPointInText& aPointToInsert) {
     30  MOZ_ASSERT(aPointToInsert.IsSetAndValid());
     31  RefPtr<InsertTextTransaction> transaction =
     32      aEditorBase.IsTextEditor()
     33          ? new InsertTextTransaction(aEditorBase, aStringToInsert,
     34                                      aPointToInsert)
     35          : new InsertTextIntoTextNodeTransaction(aEditorBase, aStringToInsert,
     36                                                  aPointToInsert);
     37  return transaction.forget();
     38 }
     39 
     40 InsertTextTransaction::InsertTextTransaction(
     41    EditorBase& aEditorBase, const nsAString& aStringToInsert,
     42    const EditorDOMPointInText& aPointToInsert)
     43    : mEditorBase(&aEditorBase),
     44      mStringToInsert(aStringToInsert),
     45      mOffset(aPointToInsert.Offset()) {}
     46 
     47 std::ostream& operator<<(std::ostream& aStream,
     48                         const InsertTextTransaction& aTransaction) {
     49  const auto* transactionForHTMLEditor =
     50      aTransaction.GetAsInsertTextIntoTextNodeTransaction();
     51  if (transactionForHTMLEditor) {
     52    return aStream << *transactionForHTMLEditor;
     53  }
     54  aStream << "{ mOffset=" << aTransaction.mOffset << ", mStringToInsert=\""
     55          << NS_ConvertUTF16toUTF8(aTransaction.mStringToInsert).get() << "\""
     56          << ", mEditorBase=" << aTransaction.mEditorBase.get() << " }";
     57  return aStream;
     58 }
     59 
     60 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase,
     61                                   mEditorBase)
     62 
     63 NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase)
     64 NS_IMPL_RELEASE_INHERITED(InsertTextTransaction, EditTransactionBase)
     65 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTransaction)
     66 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
     67 
     68 Text* InsertTextTransaction::GetTextNode() const {
     69  if (MOZ_UNLIKELY(!mEditorBase)) {
     70    return nullptr;
     71  }
     72  if (TextEditor* const textEditor = mEditorBase->GetAsTextEditor()) {
     73    return textEditor->GetTextNode();
     74  }
     75  MOZ_ASSERT(GetAsInsertTextIntoTextNodeTransaction());
     76  return GetAsInsertTextIntoTextNodeTransaction()->mTextNode;
     77 }
     78 
     79 NS_IMETHODIMP InsertTextTransaction::DoTransaction() {
     80  MOZ_LOG(GetLogModule(), LogLevel::Info,
     81          ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__,
     82           ToString(*this).c_str()));
     83 
     84  if (NS_WARN_IF(!mEditorBase)) {
     85    return NS_ERROR_NOT_AVAILABLE;
     86  }
     87 
     88  const RefPtr<Text> textNode = GetTextNode();
     89  if (NS_WARN_IF(!textNode)) {
     90    return NS_ERROR_NOT_AVAILABLE;
     91  }
     92 
     93  const OwningNonNull<EditorBase> editorBase = *mEditorBase;
     94  ErrorResult error;
     95  editorBase->DoInsertText(*textNode, mOffset, mStringToInsert, error);
     96  if (error.Failed()) {
     97    NS_WARNING("EditorBase::DoInsertText() failed");
     98    return error.StealNSResult();
     99  }
    100 
    101  editorBase->RangeUpdaterRef().SelAdjInsertText(*textNode, mOffset,
    102                                                 mStringToInsert.Length());
    103  return NS_OK;
    104 }
    105 
    106 NS_IMETHODIMP InsertTextTransaction::UndoTransaction() {
    107  MOZ_LOG(GetLogModule(), LogLevel::Info,
    108          ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__,
    109           ToString(*this).c_str()));
    110 
    111  if (NS_WARN_IF(!mEditorBase)) {
    112    return NS_ERROR_NOT_INITIALIZED;
    113  }
    114 
    115  const RefPtr<Text> textNode = GetTextNode();
    116  if (NS_WARN_IF(!textNode)) {
    117    return NS_ERROR_NOT_AVAILABLE;
    118  }
    119 
    120  const OwningNonNull<EditorBase> editorBase = *mEditorBase;
    121  ErrorResult error;
    122  editorBase->DoDeleteText(*textNode, mOffset, mStringToInsert.Length(), error);
    123  NS_WARNING_ASSERTION(!error.Failed(), "EditorBase::DoDeleteText() failed");
    124  return error.StealNSResult();
    125 }
    126 
    127 NS_IMETHODIMP InsertTextTransaction::RedoTransaction() {
    128  MOZ_LOG(GetLogModule(), LogLevel::Info,
    129          ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__,
    130           !mEditorBase || mEditorBase->IsTextEditor()
    131               ? ToString(*this).c_str()
    132               : ToString(*GetAsInsertTextIntoTextNodeTransaction()).c_str()));
    133  nsresult rv = DoTransaction();
    134  if (NS_FAILED(rv)) {
    135    NS_WARNING("InsertTextTransaction::DoTransaction() failed");
    136    return rv;
    137  }
    138  if (RefPtr<EditorBase> editorBase = mEditorBase) {
    139    nsresult rv = editorBase->CollapseSelectionTo(
    140        SuggestPointToPutCaret<EditorRawDOMPoint>());
    141    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
    142      return NS_ERROR_EDITOR_DESTROYED;
    143    }
    144    NS_WARNING_ASSERTION(
    145        NS_SUCCEEDED(rv),
    146        "EditorBase::CollapseSelectionTo() failed, but ignored");
    147  }
    148  return NS_OK;
    149 }
    150 
    151 NS_IMETHODIMP InsertTextTransaction::Merge(nsITransaction* aOtherTransaction,
    152                                           bool* aDidMerge) {
    153  MOZ_LOG(GetLogModule(), LogLevel::Debug,
    154          ("%p InsertTextTransaction::%s(aOtherTransaction=%p) this=%s", this,
    155           __FUNCTION__, aOtherTransaction, ToString(*this).c_str()));
    156 
    157  if (NS_WARN_IF(!aOtherTransaction) || NS_WARN_IF(!aDidMerge)) {
    158    return NS_ERROR_INVALID_ARG;
    159  }
    160  // Set out param default value
    161  *aDidMerge = false;
    162 
    163  RefPtr<EditTransactionBase> otherTransactionBase =
    164      aOtherTransaction->GetAsEditTransactionBase();
    165  if (!otherTransactionBase) {
    166    MOZ_LOG(
    167        GetLogModule(), LogLevel::Debug,
    168        ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
    169         this, __FUNCTION__, aOtherTransaction));
    170    return NS_OK;
    171  }
    172 
    173  // If aTransaction is a InsertTextTransaction, and if the selection hasn't
    174  // changed, then absorb it.
    175  InsertTextTransaction* otherInsertTextTransaction =
    176      otherTransactionBase->GetAsInsertTextTransaction();
    177  if (!otherInsertTextTransaction ||
    178      !IsSequentialInsert(*otherInsertTextTransaction)) {
    179    MOZ_LOG(
    180        GetLogModule(), LogLevel::Debug,
    181        ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
    182         this, __FUNCTION__, aOtherTransaction));
    183    return NS_OK;
    184  }
    185 
    186  mStringToInsert += otherInsertTextTransaction->GetData();
    187  *aDidMerge = true;
    188  MOZ_LOG(GetLogModule(), LogLevel::Debug,
    189          ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned true",
    190           this, __FUNCTION__, aOtherTransaction));
    191  return NS_OK;
    192 }
    193 
    194 bool InsertTextTransaction::IsSequentialInsert(
    195    InsertTextTransaction& aOtherTransaction) const {
    196  return aOtherTransaction.GetTextNode() == GetTextNode() &&
    197         aOtherTransaction.mOffset == mOffset + mStringToInsert.Length();
    198 }
    199 
    200 /******************************************************************************
    201 * mozilla::InsertTextIntoTextNodeTransaction
    202 ******************************************************************************/
    203 
    204 InsertTextIntoTextNodeTransaction::InsertTextIntoTextNodeTransaction(
    205    EditorBase& aEditorBase, const nsAString& aStringToInsert,
    206    const EditorDOMPointInText& aPointToInsert)
    207    : InsertTextTransaction(aEditorBase, aStringToInsert, aPointToInsert),
    208      mTextNode(aPointToInsert.ContainerAs<Text>()) {
    209  MOZ_ASSERT(aEditorBase.IsHTMLEditor());
    210 }
    211 
    212 std::ostream& operator<<(
    213    std::ostream& aStream,
    214    const InsertTextIntoTextNodeTransaction& aTransaction) {
    215  aStream << "{ mTextNode=" << aTransaction.mTextNode.get();
    216  if (aTransaction.mTextNode) {
    217    aStream << " (" << *aTransaction.mTextNode << ")";
    218  }
    219  aStream << ", mOffset=" << aTransaction.mOffset << ", mStringToInsert=\""
    220          << NS_ConvertUTF16toUTF8(aTransaction.mStringToInsert).get() << "\""
    221          << ", mEditorBase=" << aTransaction.mEditorBase.get() << " }";
    222  return aStream;
    223 }
    224 
    225 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextIntoTextNodeTransaction,
    226                                   InsertTextTransaction, mTextNode)
    227 
    228 NS_IMPL_ADDREF_INHERITED(InsertTextIntoTextNodeTransaction,
    229                         InsertTextTransaction)
    230 NS_IMPL_RELEASE_INHERITED(InsertTextIntoTextNodeTransaction,
    231                          InsertTextTransaction)
    232 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextIntoTextNodeTransaction)
    233 NS_INTERFACE_MAP_END_INHERITING(InsertTextTransaction)
    234 
    235 }  // namespace mozilla