LCOV - code coverage report
Current view: top level - editor/libeditor - DeleteRangeTransaction.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 100 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "DeleteRangeTransaction.h"
       7             : 
       8             : #include "DeleteNodeTransaction.h"
       9             : #include "DeleteTextTransaction.h"
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/EditorBase.h"
      12             : #include "mozilla/dom/Selection.h"
      13             : #include "mozilla/mozalloc.h"
      14             : #include "nsCOMPtr.h"
      15             : #include "nsDebug.h"
      16             : #include "nsError.h"
      17             : #include "nsIContent.h"
      18             : #include "nsIContentIterator.h"
      19             : #include "nsINode.h"
      20             : #include "nsAString.h"
      21             : 
      22             : namespace mozilla {
      23             : 
      24             : using namespace dom;
      25             : 
      26             : // note that aEditorBase is not refcounted
      27           0 : DeleteRangeTransaction::DeleteRangeTransaction(EditorBase& aEditorBase,
      28             :                                                nsRange& aRangeToDelete,
      29           0 :                                                RangeUpdater* aRangeUpdater)
      30             :   : mEditorBase(&aEditorBase)
      31           0 :   , mRangeToDelete(aRangeToDelete.CloneRange())
      32           0 :   , mRangeUpdater(aRangeUpdater)
      33             : {
      34           0 : }
      35             : 
      36           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteRangeTransaction,
      37             :                                    EditAggregateTransaction,
      38             :                                    mEditorBase,
      39             :                                    mRangeToDelete)
      40             : 
      41           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteRangeTransaction)
      42           0 : NS_INTERFACE_MAP_END_INHERITING(EditAggregateTransaction)
      43             : 
      44             : NS_IMETHODIMP
      45           0 : DeleteRangeTransaction::DoTransaction()
      46             : {
      47           0 :   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mRangeToDelete)) {
      48           0 :     return NS_ERROR_NOT_AVAILABLE;
      49             :   }
      50             : 
      51             :   // Swap mRangeToDelete out into a stack variable, so we make sure to null it
      52             :   // out on return from this function.  Once this function returns, we no longer
      53             :   // need mRangeToDelete, and keeping it alive in the long term slows down all
      54             :   // DOM mutations because it's observing them.
      55           0 :   RefPtr<nsRange> rangeToDelete;
      56           0 :   rangeToDelete.swap(mRangeToDelete);
      57             : 
      58             :   // build the child transactions
      59           0 :   nsCOMPtr<nsINode> startContainer = rangeToDelete->GetStartContainer();
      60           0 :   int32_t startOffset = rangeToDelete->StartOffset();
      61           0 :   nsCOMPtr<nsINode> endContainer = rangeToDelete->GetEndContainer();
      62           0 :   int32_t endOffset = rangeToDelete->EndOffset();
      63           0 :   MOZ_ASSERT(startContainer && endContainer);
      64             : 
      65           0 :   if (startContainer == endContainer) {
      66             :     // the selection begins and ends in the same node
      67             :     nsresult rv =
      68           0 :       CreateTxnsToDeleteBetween(startContainer, startOffset, endOffset);
      69           0 :     NS_ENSURE_SUCCESS(rv, rv);
      70             :   } else {
      71             :     // the selection ends in a different node from where it started.  delete
      72             :     // the relevant content in the start node
      73             :     nsresult rv =
      74           0 :       CreateTxnsToDeleteContent(startContainer, startOffset, nsIEditor::eNext);
      75           0 :     NS_ENSURE_SUCCESS(rv, rv);
      76             :     // delete the intervening nodes
      77           0 :     rv = CreateTxnsToDeleteNodesBetween(rangeToDelete);
      78           0 :     NS_ENSURE_SUCCESS(rv, rv);
      79             :     // delete the relevant content in the end node
      80           0 :     rv = CreateTxnsToDeleteContent(endContainer, endOffset,
      81           0 :                                    nsIEditor::ePrevious);
      82           0 :     NS_ENSURE_SUCCESS(rv, rv);
      83             :   }
      84             : 
      85             :   // if we've successfully built this aggregate transaction, then do it.
      86           0 :   nsresult rv = EditAggregateTransaction::DoTransaction();
      87           0 :   NS_ENSURE_SUCCESS(rv, rv);
      88             : 
      89             :   // only set selection to deletion point if editor gives permission
      90             :   bool bAdjustSelection;
      91           0 :   mEditorBase->ShouldTxnSetSelection(&bAdjustSelection);
      92           0 :   if (bAdjustSelection) {
      93           0 :     RefPtr<Selection> selection = mEditorBase->GetSelection();
      94           0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
      95           0 :     rv = selection->Collapse(startContainer, startOffset);
      96           0 :     NS_ENSURE_SUCCESS(rv, rv);
      97             :   }
      98             :   // else do nothing - dom range gravity will adjust selection
      99             : 
     100           0 :   return NS_OK;
     101             : }
     102             : 
     103             : NS_IMETHODIMP
     104           0 : DeleteRangeTransaction::UndoTransaction()
     105             : {
     106           0 :   return EditAggregateTransaction::UndoTransaction();
     107             : }
     108             : 
     109             : NS_IMETHODIMP
     110           0 : DeleteRangeTransaction::RedoTransaction()
     111             : {
     112           0 :   return EditAggregateTransaction::RedoTransaction();
     113             : }
     114             : 
     115             : NS_IMETHODIMP
     116           0 : DeleteRangeTransaction::GetTxnDescription(nsAString& aString)
     117             : {
     118           0 :   aString.AssignLiteral("DeleteRangeTransaction");
     119           0 :   return NS_OK;
     120             : }
     121             : 
     122             : nsresult
     123           0 : DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
     124             :                                                   int32_t aStartOffset,
     125             :                                                   int32_t aEndOffset)
     126             : {
     127           0 :   if (NS_WARN_IF(!mEditorBase)) {
     128           0 :     return NS_ERROR_NOT_AVAILABLE;
     129             :   }
     130             : 
     131             :   // see what kind of node we have
     132           0 :   if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
     133             :     // if the node is a chardata node, then delete chardata content
     134             :     int32_t numToDel;
     135           0 :     if (aStartOffset == aEndOffset) {
     136           0 :       numToDel = 1;
     137             :     } else {
     138           0 :       numToDel = aEndOffset - aStartOffset;
     139             :     }
     140             : 
     141             :     RefPtr<nsGenericDOMDataNode> charDataNode =
     142           0 :       static_cast<nsGenericDOMDataNode*>(aNode);
     143             : 
     144             :     RefPtr<DeleteTextTransaction> deleteTextTransaction =
     145           0 :       new DeleteTextTransaction(*mEditorBase, *charDataNode, aStartOffset,
     146           0 :                                 numToDel, mRangeUpdater);
     147             :     // If the text node isn't editable, it should be never undone/redone.
     148             :     // So, the transaction shouldn't be recorded.
     149           0 :     if (NS_WARN_IF(!deleteTextTransaction->CanDoIt())) {
     150           0 :       return NS_ERROR_FAILURE;
     151             :     }
     152           0 :     AppendChild(deleteTextTransaction);
     153           0 :     return NS_OK;
     154             :   }
     155             : 
     156           0 :   nsCOMPtr<nsIContent> child = aNode->GetChildAt(aStartOffset);
     157           0 :   for (int32_t i = aStartOffset; i < aEndOffset; ++i) {
     158             :     // Even if we detect invalid range, we should ignore it for removing
     159             :     // specified range's nodes as far as possible.
     160           0 :     if (NS_WARN_IF(!child)) {
     161           0 :       break;
     162             :     }
     163             :     RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
     164           0 :       new DeleteNodeTransaction(*mEditorBase, *child, mRangeUpdater);
     165             :     // XXX This is odd handling.  Even if some children are not editable,
     166             :     //     editor should append transactions because they could be editable
     167             :     //     at undoing/redoing.  Additionally, if the transaction needs to
     168             :     //     delete/restore all nodes, it should at undoing/redoing.
     169           0 :     if (deleteNodeTransaction->CanDoIt()) {
     170           0 :       AppendChild(deleteNodeTransaction);
     171             :     }
     172           0 :     child = child->GetNextSibling();
     173             :   }
     174             : 
     175           0 :   return NS_OK;
     176             : }
     177             : 
     178             : nsresult
     179           0 : DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
     180             :                                                   int32_t aOffset,
     181             :                                                   nsIEditor::EDirection aAction)
     182             : {
     183           0 :   if (NS_WARN_IF(!mEditorBase)) {
     184           0 :     return NS_ERROR_NOT_AVAILABLE;
     185             :   }
     186             : 
     187             :   // see what kind of node we have
     188           0 :   if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
     189             :     // if the node is a chardata node, then delete chardata content
     190             :     uint32_t start, numToDelete;
     191           0 :     if (nsIEditor::eNext == aAction) {
     192           0 :       start = aOffset;
     193           0 :       numToDelete = aNode->Length() - aOffset;
     194             :     } else {
     195           0 :       start = 0;
     196           0 :       numToDelete = aOffset;
     197             :     }
     198             : 
     199           0 :     if (numToDelete) {
     200             :       RefPtr<nsGenericDOMDataNode> dataNode =
     201           0 :         static_cast<nsGenericDOMDataNode*>(aNode);
     202             :       RefPtr<DeleteTextTransaction> deleteTextTransaction =
     203           0 :         new DeleteTextTransaction(*mEditorBase, *dataNode, start, numToDelete,
     204           0 :                                   mRangeUpdater);
     205             :       // If the text node isn't editable, it should be never undone/redone.
     206             :       // So, the transaction shouldn't be recorded.
     207           0 :       if (NS_WARN_IF(!deleteTextTransaction->CanDoIt())) {
     208           0 :         return NS_ERROR_FAILURE;
     209             :       }
     210           0 :       AppendChild(deleteTextTransaction);
     211             :     }
     212             :   }
     213             : 
     214           0 :   return NS_OK;
     215             : }
     216             : 
     217             : nsresult
     218           0 : DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween(nsRange* aRangeToDelete)
     219             : {
     220           0 :   if (NS_WARN_IF(!mEditorBase)) {
     221           0 :     return NS_ERROR_NOT_AVAILABLE;
     222             :   }
     223             : 
     224           0 :   nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
     225             : 
     226           0 :   nsresult rv = iter->Init(aRangeToDelete);
     227           0 :   NS_ENSURE_SUCCESS(rv, rv);
     228             : 
     229           0 :   while (!iter->IsDone()) {
     230           0 :     nsCOMPtr<nsINode> node = iter->GetCurrentNode();
     231           0 :     if (NS_WARN_IF(!node)) {
     232           0 :       return NS_ERROR_NULL_POINTER;
     233             :     }
     234             : 
     235             :     RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
     236           0 :       new DeleteNodeTransaction(*mEditorBase, *node, mRangeUpdater);
     237             :     // XXX This is odd handling.  Even if some nodes in the range are not
     238             :     //     editable, editor should append transactions because they could
     239             :     //     at undoing/redoing.  Additionally, if the transaction needs to
     240             :     //     delete/restore all nodes, it should at undoing/redoing.
     241           0 :     if (NS_WARN_IF(!deleteNodeTransaction->CanDoIt())) {
     242           0 :       return NS_ERROR_FAILURE;
     243             :     }
     244           0 :     AppendChild(deleteNodeTransaction);
     245             : 
     246           0 :     iter->Next();
     247             :   }
     248           0 :   return NS_OK;
     249             : }
     250             : 
     251             : } // namespace mozilla

Generated by: LCOV version 1.13