mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 13:07:52 +00:00
Bug 1415414 - Make DeleteRangeTransaction::CreateTxnsToDeleteBetween() and DeleteRangeTransaction::CreateTxnsToDeleteContent() use RawRangeBoundary as their arguments r=m_kato
By the fix of bug 1407352, DeleteRangeTransaction::CreateTxnsToDeleteBetween() starts to use child node instead of a set of container node and offset in it. However, this is ugly and using RawRangeBoundary may reduce computing offset more. So, they should use RawRangeBoundary to refer delete points. MozReview-Commit-ID: pwDHOxpz0E --HG-- extra : rebase_source : 3871ba4fa3cfb174d5dac57822ae69c40a305323
This commit is contained in:
parent
223e6dec30
commit
7c53b094a1
@ -11,6 +11,7 @@
|
||||
#include "mozilla/EditorBase.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/RangeBoundary.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
@ -56,46 +57,54 @@ DeleteRangeTransaction::DoTransaction()
|
||||
rangeToDelete.swap(mRangeToDelete);
|
||||
|
||||
// build the child transactions
|
||||
nsCOMPtr<nsINode> startContainer = rangeToDelete->GetStartContainer();
|
||||
int32_t startOffset = rangeToDelete->StartOffset();
|
||||
nsCOMPtr<nsINode> endContainer = rangeToDelete->GetEndContainer();
|
||||
int32_t endOffset = rangeToDelete->EndOffset();
|
||||
MOZ_ASSERT(startContainer && endContainer);
|
||||
const RangeBoundary& startRef = rangeToDelete->StartRef();
|
||||
const RangeBoundary& endRef = rangeToDelete->EndRef();
|
||||
MOZ_ASSERT(startRef.IsSetAndValid());
|
||||
MOZ_ASSERT(endRef.IsSetAndValid());
|
||||
|
||||
if (startContainer == endContainer) {
|
||||
if (startRef.Container() == endRef.Container()) {
|
||||
// the selection begins and ends in the same node
|
||||
nsIContent* startChild = rangeToDelete->GetChildAtStartOffset();
|
||||
nsresult rv =
|
||||
CreateTxnsToDeleteBetween(startContainer, startOffset,
|
||||
startChild, endOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = CreateTxnsToDeleteBetween(startRef.AsRaw(), endRef.AsRaw());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
// the selection ends in a different node from where it started. delete
|
||||
// the relevant content in the start node
|
||||
nsresult rv =
|
||||
CreateTxnsToDeleteContent(startContainer, startOffset, nsIEditor::eNext);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = CreateTxnsToDeleteContent(startRef.AsRaw(), nsIEditor::eNext);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
// delete the intervening nodes
|
||||
rv = CreateTxnsToDeleteNodesBetween(rangeToDelete);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
// delete the relevant content in the end node
|
||||
rv = CreateTxnsToDeleteContent(endContainer, endOffset,
|
||||
nsIEditor::ePrevious);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = CreateTxnsToDeleteContent(endRef.AsRaw(), nsIEditor::ePrevious);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've successfully built this aggregate transaction, then do it.
|
||||
nsresult rv = EditAggregateTransaction::DoTransaction();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// only set selection to deletion point if editor gives permission
|
||||
bool bAdjustSelection;
|
||||
mEditorBase->ShouldTxnSetSelection(&bAdjustSelection);
|
||||
if (bAdjustSelection) {
|
||||
RefPtr<Selection> selection = mEditorBase->GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
rv = selection->Collapse(startContainer, startOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
rv = selection->Collapse(startRef.AsRaw());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
// else do nothing - dom range gravity will adjust selection
|
||||
|
||||
@ -122,30 +131,36 @@ DeleteRangeTransaction::GetTxnDescription(nsAString& aString)
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||
int32_t aStartOffset,
|
||||
nsIContent* aChildAtStartOffset,
|
||||
int32_t aEndOffset)
|
||||
DeleteRangeTransaction::CreateTxnsToDeleteBetween(
|
||||
const RawRangeBoundary& aStart,
|
||||
const RawRangeBoundary& aEnd)
|
||||
{
|
||||
if (NS_WARN_IF(!aStart.IsSetAndValid()) ||
|
||||
NS_WARN_IF(!aEnd.IsSetAndValid()) ||
|
||||
NS_WARN_IF(aStart.Container() != aEnd.Container())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mEditorBase)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// see what kind of node we have
|
||||
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
|
||||
if (aStart.Container()->IsNodeOfType(nsINode::eDATA_NODE)) {
|
||||
// if the node is a chardata node, then delete chardata content
|
||||
int32_t numToDel;
|
||||
if (aStartOffset == aEndOffset) {
|
||||
if (aStart == aEnd) {
|
||||
numToDel = 1;
|
||||
} else {
|
||||
numToDel = aEndOffset - aStartOffset;
|
||||
numToDel = aEnd.Offset() - aStart.Offset();
|
||||
MOZ_DIAGNOSTIC_ASSERT(numToDel > 0);
|
||||
}
|
||||
|
||||
RefPtr<nsGenericDOMDataNode> charDataNode =
|
||||
static_cast<nsGenericDOMDataNode*>(aNode);
|
||||
static_cast<nsGenericDOMDataNode*>(aStart.Container());
|
||||
|
||||
RefPtr<DeleteTextTransaction> deleteTextTransaction =
|
||||
new DeleteTextTransaction(*mEditorBase, *charDataNode, aStartOffset,
|
||||
new DeleteTextTransaction(*mEditorBase, *charDataNode, aStart.Offset(),
|
||||
numToDel, mRangeUpdater);
|
||||
// If the text node isn't editable, it should be never undone/redone.
|
||||
// So, the transaction shouldn't be recorded.
|
||||
@ -156,13 +171,11 @@ DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent* child = aChildAtStartOffset;
|
||||
for (int32_t i = aStartOffset; i < aEndOffset; ++i) {
|
||||
// Even if we detect invalid range, we should ignore it for removing
|
||||
// specified range's nodes as far as possible.
|
||||
if (NS_WARN_IF(!child)) {
|
||||
break;
|
||||
}
|
||||
// Even if we detect invalid range, we should ignore it for removing
|
||||
// specified range's nodes as far as possible.
|
||||
for (nsIContent* child = aStart.GetChildAtOffset();
|
||||
child && child != aEnd.GetChildAtOffset();
|
||||
child = child->GetNextSibling()) {
|
||||
RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
|
||||
new DeleteNodeTransaction(*mEditorBase, *child, mRangeUpdater);
|
||||
// XXX This is odd handling. Even if some children are not editable,
|
||||
@ -172,48 +185,54 @@ DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||
if (deleteNodeTransaction->CanDoIt()) {
|
||||
AppendChild(deleteNodeTransaction);
|
||||
}
|
||||
child = child->GetNextSibling();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
|
||||
int32_t aOffset,
|
||||
nsIEditor::EDirection aAction)
|
||||
DeleteRangeTransaction::CreateTxnsToDeleteContent(
|
||||
const RawRangeBoundary& aPoint,
|
||||
nsIEditor::EDirection aAction)
|
||||
{
|
||||
if (NS_WARN_IF(!aPoint.IsSetAndValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mEditorBase)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// see what kind of node we have
|
||||
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
|
||||
// if the node is a chardata node, then delete chardata content
|
||||
uint32_t start, numToDelete;
|
||||
if (nsIEditor::eNext == aAction) {
|
||||
start = aOffset;
|
||||
numToDelete = aNode->Length() - aOffset;
|
||||
} else {
|
||||
start = 0;
|
||||
numToDelete = aOffset;
|
||||
}
|
||||
|
||||
if (numToDelete) {
|
||||
RefPtr<nsGenericDOMDataNode> dataNode =
|
||||
static_cast<nsGenericDOMDataNode*>(aNode);
|
||||
RefPtr<DeleteTextTransaction> deleteTextTransaction =
|
||||
new DeleteTextTransaction(*mEditorBase, *dataNode, start, numToDelete,
|
||||
mRangeUpdater);
|
||||
// If the text node isn't editable, it should be never undone/redone.
|
||||
// So, the transaction shouldn't be recorded.
|
||||
if (NS_WARN_IF(!deleteTextTransaction->CanDoIt())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
AppendChild(deleteTextTransaction);
|
||||
}
|
||||
if (!aPoint.Container()->IsNodeOfType(nsINode::eDATA_NODE)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the node is a chardata node, then delete chardata content
|
||||
uint32_t startOffset, numToDelete;
|
||||
if (nsIEditor::eNext == aAction) {
|
||||
startOffset = aPoint.Offset();
|
||||
numToDelete = aPoint.Container()->Length() - aPoint.Offset();
|
||||
} else {
|
||||
startOffset = 0;
|
||||
numToDelete = aPoint.Offset();
|
||||
}
|
||||
|
||||
if (!numToDelete) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsGenericDOMDataNode> dataNode =
|
||||
static_cast<nsGenericDOMDataNode*>(aPoint.Container());
|
||||
RefPtr<DeleteTextTransaction> deleteTextTransaction =
|
||||
new DeleteTextTransaction(*mEditorBase, *dataNode, startOffset, numToDelete,
|
||||
mRangeUpdater);
|
||||
// If the text node isn't editable, it should be never undone/redone.
|
||||
// So, the transaction shouldn't be recorded.
|
||||
if (NS_WARN_IF(!deleteTextTransaction->CanDoIt())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
AppendChild(deleteTextTransaction);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define DeleteRangeTransaction_h
|
||||
|
||||
#include "EditAggregateTransaction.h"
|
||||
#include "mozilla/RangeBoundary.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsID.h"
|
||||
#include "nsIEditor.h"
|
||||
@ -50,15 +51,53 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
nsresult CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||
int32_t aStartOffset,
|
||||
nsIContent* aChildAtStartOffset,
|
||||
int32_t aEndOffset);
|
||||
/**
|
||||
* CreateTxnsToDeleteBetween() creates a DeleteTextTransaction or some
|
||||
* DeleteNodeTransactions to remove text or nodes between aStart and aEnd
|
||||
* and appends the created transactions to the array.
|
||||
*
|
||||
* @param aStart Must be set and valid point.
|
||||
* @param aEnd Must be set and valid point. Additionally, the
|
||||
* container must be same as aStart's container.
|
||||
* And of course, this must not be before aStart in
|
||||
* the DOM tree order.
|
||||
* @return Returns NS_OK in most cases.
|
||||
* When the arguments are invalid, returns
|
||||
* NS_ERROR_INVALID_ARG.
|
||||
* When mEditorBase isn't available, returns
|
||||
* NS_ERROR_NOT_AVAIALBLE.
|
||||
* When created DeleteTextTransaction cannot do its
|
||||
* transaction, returns NS_ERROR_FAILURE.
|
||||
* Note that even if one of created DeleteNodeTransaction
|
||||
* cannot do its transaction, this returns NS_OK.
|
||||
*/
|
||||
nsresult CreateTxnsToDeleteBetween(const RawRangeBoundary& aStart,
|
||||
const RawRangeBoundary& aEnd);
|
||||
|
||||
nsresult CreateTxnsToDeleteNodesBetween(nsRange* aRangeToDelete);
|
||||
|
||||
nsresult CreateTxnsToDeleteContent(nsINode* aParent,
|
||||
int32_t aOffset,
|
||||
/**
|
||||
* CreateTxnsToDeleteContent() creates a DeleteTextTransaction to delete
|
||||
* text between start of aPoint.Container() and aPoint or aPoint and end of
|
||||
* aPoint.Container() and appends the created transaction to the array.
|
||||
*
|
||||
* @param aPoint Must be set and valid point. If the container is not
|
||||
* a data node, this method does nothing.
|
||||
* @param aAction If nsIEditor::eNext, this method creates a transaction
|
||||
* to delete text from aPoint to the end of the data node.
|
||||
* Otherwise, this method creates a transaction to delete
|
||||
* text from start of the data node to aPoint.
|
||||
* @return Returns NS_OK in most cases.
|
||||
* When the arguments are invalid, returns
|
||||
* NS_ERROR_INVALID_ARG.
|
||||
* When mEditorBase isn't available, returns
|
||||
* NS_ERROR_NOT_AVAIALBLE.
|
||||
* When created DeleteTextTransaction cannot do its
|
||||
* transaction, returns NS_ERROR_FAILURE.
|
||||
* Note that even if no character will be deleted,
|
||||
* this returns NS_OK.
|
||||
*/
|
||||
nsresult CreateTxnsToDeleteContent(const RawRangeBoundary& aPoint,
|
||||
nsIEditor::EDirection aAction);
|
||||
|
||||
// The editor for this transaction.
|
||||
|
Loading…
x
Reference in New Issue
Block a user