mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
61af94acbd
nsRange::DoSetRange() adds/remove its root to/from mutation observer, initializes common ancestor, registers itself to the common ancestor, unregisters itself from old common ancestor, and notifies selection listeners of selection change. However, those runtime cost is expensive but on the other hand, a lot of callers set both start and end of the range and that causes calling DoSetRange() twice. This patch renames Set() to SetStartAndEnd() for easier to understand the meaning and make it call DoSetRange() only once. MozReview-Commit-ID: FRV55tuBAgg --HG-- extra : rebase_source : 67adf929cf119e2425f7d3741651217522094590
697 lines
17 KiB
C++
697 lines
17 KiB
C++
/* -*- 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 "mozilla/SelectionState.h"
|
|
|
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
|
|
#include "mozilla/EditorUtils.h" // for EditorUtils
|
|
#include "mozilla/dom/Selection.h" // for Selection
|
|
#include "nsAString.h" // for nsAString::Length
|
|
#include "nsCycleCollectionParticipant.h"
|
|
#include "nsDebug.h" // for NS_ENSURE_TRUE, etc.
|
|
#include "nsError.h" // for NS_OK, etc.
|
|
#include "nsIContent.h" // for nsIContent
|
|
#include "nsIDOMCharacterData.h" // for nsIDOMCharacterData
|
|
#include "nsIDOMNode.h" // for nsIDOMNode
|
|
#include "nsISupportsImpl.h" // for nsRange::Release
|
|
#include "nsRange.h" // for nsRange
|
|
|
|
namespace mozilla {
|
|
|
|
using namespace dom;
|
|
|
|
/******************************************************************************
|
|
* mozilla::SelectionState
|
|
*
|
|
* Class for recording selection info. Stores selection as collection of
|
|
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Can't store
|
|
* ranges since dom gravity will possibly change the ranges.
|
|
******************************************************************************/
|
|
SelectionState::SelectionState()
|
|
{
|
|
}
|
|
|
|
SelectionState::~SelectionState()
|
|
{
|
|
MakeEmpty();
|
|
}
|
|
|
|
void
|
|
SelectionState::SaveSelection(Selection* aSel)
|
|
{
|
|
MOZ_ASSERT(aSel);
|
|
int32_t arrayCount = mArray.Length();
|
|
int32_t rangeCount = aSel->RangeCount();
|
|
|
|
// if we need more items in the array, new them
|
|
if (arrayCount < rangeCount) {
|
|
for (int32_t i = arrayCount; i < rangeCount; i++) {
|
|
mArray.AppendElement();
|
|
mArray[i] = new RangeItem();
|
|
}
|
|
} else if (arrayCount > rangeCount) {
|
|
// else if we have too many, delete them
|
|
for (int32_t i = arrayCount - 1; i >= rangeCount; i--) {
|
|
mArray.RemoveElementAt(i);
|
|
}
|
|
}
|
|
|
|
// now store the selection ranges
|
|
for (int32_t i = 0; i < rangeCount; i++) {
|
|
mArray[i]->StoreRange(aSel->GetRangeAt(i));
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
SelectionState::RestoreSelection(Selection* aSel)
|
|
{
|
|
NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
|
|
|
|
// clear out selection
|
|
aSel->RemoveAllRanges();
|
|
|
|
// set the selection ranges anew
|
|
size_t arrayCount = mArray.Length();
|
|
for (size_t i = 0; i < arrayCount; i++) {
|
|
RefPtr<nsRange> range = mArray[i]->GetRange();
|
|
NS_ENSURE_TRUE(range, NS_ERROR_UNEXPECTED);
|
|
|
|
nsresult rv = aSel->AddRange(range);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
SelectionState::IsCollapsed()
|
|
{
|
|
if (mArray.Length() != 1) {
|
|
return false;
|
|
}
|
|
RefPtr<nsRange> range = mArray[0]->GetRange();
|
|
NS_ENSURE_TRUE(range, false);
|
|
bool bIsCollapsed = false;
|
|
range->GetCollapsed(&bIsCollapsed);
|
|
return bIsCollapsed;
|
|
}
|
|
|
|
bool
|
|
SelectionState::IsEqual(SelectionState* aSelState)
|
|
{
|
|
NS_ENSURE_TRUE(aSelState, false);
|
|
size_t myCount = mArray.Length(), itsCount = aSelState->mArray.Length();
|
|
if (myCount != itsCount) {
|
|
return false;
|
|
}
|
|
if (!myCount) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < myCount; i++) {
|
|
RefPtr<nsRange> myRange = mArray[i]->GetRange();
|
|
RefPtr<nsRange> itsRange = aSelState->mArray[i]->GetRange();
|
|
NS_ENSURE_TRUE(myRange && itsRange, false);
|
|
|
|
int16_t compResult;
|
|
nsresult rv;
|
|
rv = myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
|
|
if (NS_FAILED(rv) || compResult) {
|
|
return false;
|
|
}
|
|
rv = myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
|
|
if (NS_FAILED(rv) || compResult) {
|
|
return false;
|
|
}
|
|
}
|
|
// if we got here, they are equal
|
|
return true;
|
|
}
|
|
|
|
void
|
|
SelectionState::MakeEmpty()
|
|
{
|
|
// free any items in the array
|
|
mArray.Clear();
|
|
}
|
|
|
|
bool
|
|
SelectionState::IsEmpty()
|
|
{
|
|
return mArray.IsEmpty();
|
|
}
|
|
|
|
/******************************************************************************
|
|
* mozilla::RangeUpdater
|
|
*
|
|
* Class for updating nsRanges in response to editor actions.
|
|
******************************************************************************/
|
|
|
|
RangeUpdater::RangeUpdater()
|
|
: mLock(false)
|
|
{
|
|
}
|
|
|
|
RangeUpdater::~RangeUpdater()
|
|
{
|
|
// nothing to do, we don't own the items in our array.
|
|
}
|
|
|
|
void
|
|
RangeUpdater::RegisterRangeItem(RangeItem* aRangeItem)
|
|
{
|
|
if (!aRangeItem) {
|
|
return;
|
|
}
|
|
if (mArray.Contains(aRangeItem)) {
|
|
NS_ERROR("tried to register an already registered range");
|
|
return; // don't register it again. It would get doubly adjusted.
|
|
}
|
|
mArray.AppendElement(aRangeItem);
|
|
}
|
|
|
|
void
|
|
RangeUpdater::DropRangeItem(RangeItem* aRangeItem)
|
|
{
|
|
if (!aRangeItem) {
|
|
return;
|
|
}
|
|
mArray.RemoveElement(aRangeItem);
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::RegisterSelectionState(SelectionState& aSelState)
|
|
{
|
|
size_t theCount = aSelState.mArray.Length();
|
|
if (theCount < 1) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
for (size_t i = 0; i < theCount; i++) {
|
|
RegisterRangeItem(aSelState.mArray[i]);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::DropSelectionState(SelectionState& aSelState)
|
|
{
|
|
size_t theCount = aSelState.mArray.Length();
|
|
if (theCount < 1) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
for (size_t i = 0; i < theCount; i++) {
|
|
DropRangeItem(aSelState.mArray[i]);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// gravity methods:
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjCreateNode(nsINode* aParent,
|
|
int32_t aPosition)
|
|
{
|
|
if (mLock) {
|
|
// lock set by Will/DidReplaceParent, etc...
|
|
return NS_OK;
|
|
}
|
|
NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return NS_OK;
|
|
}
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
|
|
|
|
if (item->startNode == aParent && item->startOffset > aPosition) {
|
|
item->startOffset++;
|
|
}
|
|
if (item->endNode == aParent && item->endOffset > aPosition) {
|
|
item->endOffset++;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjCreateNode(nsIDOMNode* aParent,
|
|
int32_t aPosition)
|
|
{
|
|
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
|
|
return SelAdjCreateNode(parent, aPosition);
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjInsertNode(nsINode* aParent,
|
|
int32_t aPosition)
|
|
{
|
|
return SelAdjCreateNode(aParent, aPosition);
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjInsertNode(nsIDOMNode* aParent,
|
|
int32_t aPosition)
|
|
{
|
|
return SelAdjCreateNode(aParent, aPosition);
|
|
}
|
|
|
|
void
|
|
RangeUpdater::SelAdjDeleteNode(nsINode* aNode)
|
|
{
|
|
if (mLock) {
|
|
// lock set by Will/DidReplaceParent, etc...
|
|
return;
|
|
}
|
|
MOZ_ASSERT(aNode);
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsINode> parent = aNode->GetParentNode();
|
|
int32_t offset = parent ? parent->IndexOf(aNode) : -1;
|
|
|
|
// check for range endpoints that are after aNode and in the same parent
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
MOZ_ASSERT(item);
|
|
|
|
if (item->startNode == parent && item->startOffset > offset) {
|
|
item->startOffset--;
|
|
}
|
|
if (item->endNode == parent && item->endOffset > offset) {
|
|
item->endOffset--;
|
|
}
|
|
|
|
// check for range endpoints that are in aNode
|
|
if (item->startNode == aNode) {
|
|
item->startNode = parent;
|
|
item->startOffset = offset;
|
|
}
|
|
if (item->endNode == aNode) {
|
|
item->endNode = parent;
|
|
item->endOffset = offset;
|
|
}
|
|
|
|
// check for range endpoints that are in descendants of aNode
|
|
nsCOMPtr<nsINode> oldStart;
|
|
if (EditorUtils::IsDescendantOf(item->startNode, aNode)) {
|
|
oldStart = item->startNode; // save for efficiency hack below.
|
|
item->startNode = parent;
|
|
item->startOffset = offset;
|
|
}
|
|
|
|
// avoid having to call IsDescendantOf() for common case of range startnode == range endnode.
|
|
if (item->endNode == oldStart ||
|
|
EditorUtils::IsDescendantOf(item->endNode, aNode)) {
|
|
item->endNode = parent;
|
|
item->endOffset = offset;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
RangeUpdater::SelAdjDeleteNode(nsIDOMNode* aNode)
|
|
{
|
|
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
|
NS_ENSURE_TRUE_VOID(node);
|
|
return SelAdjDeleteNode(node);
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjSplitNode(nsIContent& aOldRightNode,
|
|
int32_t aOffset,
|
|
nsIContent* aNewLeftNode)
|
|
{
|
|
if (mLock) {
|
|
// lock set by Will/DidReplaceParent, etc...
|
|
return NS_OK;
|
|
}
|
|
NS_ENSURE_TRUE(aNewLeftNode, NS_ERROR_NULL_POINTER);
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsINode> parent = aOldRightNode.GetParentNode();
|
|
int32_t offset = parent ? parent->IndexOf(&aOldRightNode) : -1;
|
|
|
|
// first part is same as inserting aNewLeftnode
|
|
nsresult rv = SelAdjInsertNode(parent, offset - 1);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// next step is to check for range enpoints inside aOldRightNode
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
|
|
|
|
if (item->startNode == &aOldRightNode) {
|
|
if (item->startOffset > aOffset) {
|
|
item->startOffset -= aOffset;
|
|
} else {
|
|
item->startNode = aNewLeftNode;
|
|
}
|
|
}
|
|
if (item->endNode == &aOldRightNode) {
|
|
if (item->endOffset > aOffset) {
|
|
item->endOffset -= aOffset;
|
|
} else {
|
|
item->endNode = aNewLeftNode;
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjJoinNodes(nsINode& aLeftNode,
|
|
nsINode& aRightNode,
|
|
nsINode& aParent,
|
|
int32_t aOffset,
|
|
int32_t aOldLeftNodeLength)
|
|
{
|
|
if (mLock) {
|
|
// lock set by Will/DidReplaceParent, etc...
|
|
return NS_OK;
|
|
}
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return NS_OK;
|
|
}
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
|
|
|
|
if (item->startNode == &aParent) {
|
|
// adjust start point in aParent
|
|
if (item->startOffset > aOffset) {
|
|
item->startOffset--;
|
|
} else if (item->startOffset == aOffset) {
|
|
// join keeps right hand node
|
|
item->startNode = &aRightNode;
|
|
item->startOffset = aOldLeftNodeLength;
|
|
}
|
|
} else if (item->startNode == &aRightNode) {
|
|
// adjust start point in aRightNode
|
|
item->startOffset += aOldLeftNodeLength;
|
|
} else if (item->startNode == &aLeftNode) {
|
|
// adjust start point in aLeftNode
|
|
item->startNode = &aRightNode;
|
|
}
|
|
|
|
if (item->endNode == &aParent) {
|
|
// adjust end point in aParent
|
|
if (item->endOffset > aOffset) {
|
|
item->endOffset--;
|
|
} else if (item->endOffset == aOffset) {
|
|
// join keeps right hand node
|
|
item->endNode = &aRightNode;
|
|
item->endOffset = aOldLeftNodeLength;
|
|
}
|
|
} else if (item->endNode == &aRightNode) {
|
|
// adjust end point in aRightNode
|
|
item->endOffset += aOldLeftNodeLength;
|
|
} else if (item->endNode == &aLeftNode) {
|
|
// adjust end point in aLeftNode
|
|
item->endNode = &aRightNode;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
RangeUpdater::SelAdjInsertText(Text& aTextNode,
|
|
int32_t aOffset,
|
|
const nsAString& aString)
|
|
{
|
|
if (mLock) {
|
|
// lock set by Will/DidReplaceParent, etc...
|
|
return;
|
|
}
|
|
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return;
|
|
}
|
|
|
|
size_t len = aString.Length();
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
MOZ_ASSERT(item);
|
|
|
|
if (item->startNode == &aTextNode && item->startOffset > aOffset) {
|
|
item->startOffset += len;
|
|
}
|
|
if (item->endNode == &aTextNode && item->endOffset > aOffset) {
|
|
item->endOffset += len;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjDeleteText(nsIContent* aTextNode,
|
|
int32_t aOffset,
|
|
int32_t aLength)
|
|
{
|
|
if (mLock) {
|
|
// lock set by Will/DidReplaceParent, etc...
|
|
return NS_OK;
|
|
}
|
|
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return NS_OK;
|
|
}
|
|
NS_ENSURE_TRUE(aTextNode, NS_ERROR_NULL_POINTER);
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
|
|
|
|
if (item->startNode == aTextNode && item->startOffset > aOffset) {
|
|
item->startOffset -= aLength;
|
|
if (item->startOffset < 0) {
|
|
item->startOffset = 0;
|
|
}
|
|
}
|
|
if (item->endNode == aTextNode && item->endOffset > aOffset) {
|
|
item->endOffset -= aLength;
|
|
if (item->endOffset < 0) {
|
|
item->endOffset = 0;
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::SelAdjDeleteText(nsIDOMCharacterData* aTextNode,
|
|
int32_t aOffset,
|
|
int32_t aLength)
|
|
{
|
|
nsCOMPtr<nsIContent> textNode = do_QueryInterface(aTextNode);
|
|
return SelAdjDeleteText(textNode, aOffset, aLength);
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::WillReplaceContainer()
|
|
{
|
|
if (mLock) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
mLock = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::DidReplaceContainer(Element* aOriginalNode,
|
|
Element* aNewNode)
|
|
{
|
|
NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);
|
|
mLock = false;
|
|
|
|
NS_ENSURE_TRUE(aOriginalNode && aNewNode, NS_ERROR_NULL_POINTER);
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return NS_OK;
|
|
}
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
|
|
|
|
if (item->startNode == aOriginalNode) {
|
|
item->startNode = aNewNode;
|
|
}
|
|
if (item->endNode == aOriginalNode) {
|
|
item->endNode = aNewNode;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::WillRemoveContainer()
|
|
{
|
|
if (mLock) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
mLock = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::DidRemoveContainer(nsINode* aNode,
|
|
nsINode* aParent,
|
|
int32_t aOffset,
|
|
uint32_t aNodeOrigLen)
|
|
{
|
|
NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);
|
|
mLock = false;
|
|
|
|
NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
|
|
size_t count = mArray.Length();
|
|
if (!count) {
|
|
return NS_OK;
|
|
}
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
|
|
|
|
if (item->startNode == aNode) {
|
|
item->startNode = aParent;
|
|
item->startOffset += aOffset;
|
|
} else if (item->startNode == aParent && item->startOffset > aOffset) {
|
|
item->startOffset += (int32_t)aNodeOrigLen - 1;
|
|
}
|
|
|
|
if (item->endNode == aNode) {
|
|
item->endNode = aParent;
|
|
item->endOffset += aOffset;
|
|
} else if (item->endNode == aParent && item->endOffset > aOffset) {
|
|
item->endOffset += (int32_t)aNodeOrigLen - 1;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::DidRemoveContainer(nsIDOMNode* aNode,
|
|
nsIDOMNode* aParent,
|
|
int32_t aOffset,
|
|
uint32_t aNodeOrigLen)
|
|
{
|
|
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
|
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
|
|
return DidRemoveContainer(node, parent, aOffset, aNodeOrigLen);
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::WillInsertContainer()
|
|
{
|
|
if (mLock) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
mLock = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RangeUpdater::DidInsertContainer()
|
|
{
|
|
NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);
|
|
mLock = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
RangeUpdater::WillMoveNode()
|
|
{
|
|
mLock = true;
|
|
}
|
|
|
|
void
|
|
RangeUpdater::DidMoveNode(nsINode* aOldParent, int32_t aOldOffset,
|
|
nsINode* aNewParent, int32_t aNewOffset)
|
|
{
|
|
MOZ_ASSERT(aOldParent);
|
|
MOZ_ASSERT(aNewParent);
|
|
NS_ENSURE_TRUE_VOID(mLock);
|
|
mLock = false;
|
|
|
|
for (size_t i = 0, count = mArray.Length(); i < count; ++i) {
|
|
RangeItem* item = mArray[i];
|
|
NS_ENSURE_TRUE_VOID(item);
|
|
|
|
// like a delete in aOldParent
|
|
if (item->startNode == aOldParent && item->startOffset > aOldOffset) {
|
|
item->startOffset--;
|
|
}
|
|
if (item->endNode == aOldParent && item->endOffset > aOldOffset) {
|
|
item->endOffset--;
|
|
}
|
|
|
|
// and like an insert in aNewParent
|
|
if (item->startNode == aNewParent && item->startOffset > aNewOffset) {
|
|
item->startOffset++;
|
|
}
|
|
if (item->endNode == aNewParent && item->endOffset > aNewOffset) {
|
|
item->endOffset++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* mozilla::RangeItem
|
|
*
|
|
* Helper struct for SelectionState. This stores range endpoints.
|
|
******************************************************************************/
|
|
|
|
RangeItem::RangeItem()
|
|
{
|
|
}
|
|
|
|
RangeItem::~RangeItem()
|
|
{
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION(RangeItem, startNode, endNode)
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(RangeItem, AddRef)
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(RangeItem, Release)
|
|
|
|
void
|
|
RangeItem::StoreRange(nsRange* aRange)
|
|
{
|
|
MOZ_ASSERT(aRange);
|
|
startNode = aRange->GetStartParent();
|
|
startOffset = aRange->StartOffset();
|
|
endNode = aRange->GetEndParent();
|
|
endOffset = aRange->EndOffset();
|
|
}
|
|
|
|
already_AddRefed<nsRange>
|
|
RangeItem::GetRange()
|
|
{
|
|
RefPtr<nsRange> range = new nsRange(startNode);
|
|
if (NS_FAILED(range->SetStartAndEnd(startNode, startOffset,
|
|
endNode, endOffset))) {
|
|
return nullptr;
|
|
}
|
|
return range.forget();
|
|
}
|
|
|
|
} // namespace mozilla
|