summaryrefslogtreecommitdiffstats
path: root/dom/base/nsRange.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsRange.cpp')
-rw-r--r--dom/base/nsRange.cpp438
1 files changed, 287 insertions, 151 deletions
diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp
index d45a2c975..82e28f645 100644
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -49,6 +49,12 @@ nsRange::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return RangeBinding::Wrap(aCx, this, aGivenProto);
}
+DocGroup*
+nsRange::GetDocGroup() const
+{
+ return mOwner ? mOwner->GetDocGroup() : nullptr;
+}
+
/******************************************************
* stack based utilty class for managing monitor
******************************************************/
@@ -111,31 +117,37 @@ nsRange::CompareNodeToRange(nsINode* aNode, nsRange* aRange,
// so instead represent it by (node,0) and (node,numChildren)
parent = aNode;
nodeStart = 0;
- nodeEnd = aNode->GetChildCount();
+ uint32_t childCount = aNode->GetChildCount();
+ MOZ_ASSERT(childCount <= INT32_MAX,
+ "There shouldn't be over INT32_MAX children");
+ nodeEnd = static_cast<int32_t>(childCount);
}
else {
nodeStart = parent->IndexOf(aNode);
nodeEnd = nodeStart + 1;
+ MOZ_ASSERT(nodeStart < nodeEnd, "nodeStart shouldn't be INT32_MAX");
}
nsINode* rangeStartParent = aRange->GetStartParent();
nsINode* rangeEndParent = aRange->GetEndParent();
- int32_t rangeStartOffset = aRange->StartOffset();
- int32_t rangeEndOffset = aRange->EndOffset();
+ uint32_t rangeStartOffset = aRange->StartOffset();
+ uint32_t rangeEndOffset = aRange->EndOffset();
// is RANGE(start) <= NODE(start) ?
bool disconnected = false;
- *outNodeBefore = nsContentUtils::ComparePoints(rangeStartParent,
- rangeStartOffset,
- parent, nodeStart,
- &disconnected) > 0;
+ *outNodeBefore =
+ nsContentUtils::ComparePoints(rangeStartParent,
+ static_cast<int32_t>(rangeStartOffset),
+ parent, nodeStart,
+ &disconnected) > 0;
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
// is RANGE(end) >= NODE(end) ?
- *outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
- rangeEndOffset,
- parent, nodeEnd,
- &disconnected) < 0;
+ *outNodeAfter =
+ nsContentUtils::ComparePoints(rangeEndParent,
+ static_cast<int32_t>(rangeEndOffset),
+ parent, nodeEnd,
+ &disconnected) < 0;
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
return NS_OK;
}
@@ -164,13 +176,17 @@ struct IsItemInRangeComparator
int operator()(const nsRange* const aRange) const
{
- int32_t cmp = nsContentUtils::ComparePoints(mNode, mEndOffset,
- aRange->GetStartParent(),
- aRange->StartOffset());
+ int32_t cmp =
+ nsContentUtils::ComparePoints(
+ mNode, static_cast<int32_t>(mEndOffset),
+ aRange->GetStartParent(),
+ static_cast<int32_t>(aRange->StartOffset()));
if (cmp == 1) {
- cmp = nsContentUtils::ComparePoints(mNode, mStartOffset,
- aRange->GetEndParent(),
- aRange->EndOffset());
+ cmp =
+ nsContentUtils::ComparePoints(
+ mNode, static_cast<int32_t>(mStartOffset),
+ aRange->GetEndParent(),
+ static_cast<int32_t>(aRange->EndOffset()));
if (cmp == -1) {
return 0;
}
@@ -266,48 +282,38 @@ nsRange::nsRange(nsINode* aNode)
/* static */
nsresult
-nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset,
+nsRange::CreateRange(nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset,
nsRange** aRange)
{
- nsCOMPtr<nsIDOMNode> startDomNode = do_QueryInterface(aStartParent);
- nsCOMPtr<nsIDOMNode> endDomNode = do_QueryInterface(aEndParent);
-
- nsresult rv = CreateRange(startDomNode, aStartOffset, endDomNode, aEndOffset,
- aRange);
-
- return rv;
+ MOZ_ASSERT(aRange);
+ *aRange = nullptr;
+ RefPtr<nsRange> range = new nsRange(aStartParent);
+ nsresult rv = range->SetStartAndEnd(aStartParent, aStartOffset,
+ aEndParent, aEndOffset);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ range.forget(aRange);
+ return NS_OK;
}
/* static */
nsresult
-nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
- nsIDOMNode* aEndParent, int32_t aEndOffset,
+nsRange::CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
+ nsIDOMNode* aEndParent, uint32_t aEndOffset,
nsRange** aRange)
{
- MOZ_ASSERT(aRange);
- *aRange = nullptr;
-
nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
- NS_ENSURE_ARG_POINTER(startParent);
-
- RefPtr<nsRange> range = new nsRange(startParent);
-
- nsresult rv = range->SetStart(startParent, aStartOffset);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = range->SetEnd(aEndParent, aEndOffset);
- NS_ENSURE_SUCCESS(rv, rv);
-
- range.forget(aRange);
- return NS_OK;
+ nsCOMPtr<nsINode> endParent = do_QueryInterface(aEndParent);
+ return CreateRange(startParent, aStartOffset, endParent, aEndOffset, aRange);
}
/* static */
nsresult
-nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
- nsIDOMNode* aEndParent, int32_t aEndOffset,
+nsRange::CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
+ nsIDOMNode* aEndParent, uint32_t aEndOffset,
nsIDOMRange** aRange)
{
RefPtr<nsRange> range;
@@ -465,15 +471,27 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// again (when the new text node is notified).
nsINode* parentNode = aContent->GetParentNode();
int32_t index = -1;
- if (parentNode == mEndParent && mEndOffset > 0 &&
- (index = parentNode->IndexOf(aContent)) + 1 == mEndOffset) {
- ++mEndOffset;
- mEndOffsetWasIncremented = true;
+ if (parentNode == mEndParent && mEndOffset > 0) {
+ index = parentNode->IndexOf(aContent);
+ NS_WARNING_ASSERTION(index >= 0,
+ "Shouldn't be called during removing the node or something");
+ if (static_cast<uint32_t>(index + 1) == mEndOffset) {
+ newEndNode = mEndParent;
+ newEndOffset = mEndOffset + 1;
+ MOZ_ASSERT(IsValidOffset(newEndOffset));
+ mEndOffsetWasIncremented = true;
+ }
}
- if (parentNode == mStartParent && mStartOffset > 0 &&
- (index != -1 ? index : parentNode->IndexOf(aContent)) + 1 == mStartOffset) {
- ++mStartOffset;
- mStartOffsetWasIncremented = true;
+ if (parentNode == mStartParent && mStartOffset > 0) {
+ if (index <= 0) {
+ index = parentNode->IndexOf(aContent);
+ }
+ if (static_cast<uint32_t>(index + 1) == mStartOffset) {
+ newStartNode = mStartParent;
+ newStartOffset = mStartOffset + 1;
+ MOZ_ASSERT(IsValidOffset(newStartOffset));
+ mStartOffsetWasIncremented = true;
+ }
}
#ifdef DEBUG
if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
@@ -486,16 +504,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// If the changed node contains our start boundary and the change starts
// before the boundary we'll need to adjust the offset.
- if (aContent == mStartParent &&
- aInfo->mChangeStart < static_cast<uint32_t>(mStartOffset)) {
+ if (aContent == mStartParent && aInfo->mChangeStart < mStartOffset) {
if (aInfo->mDetails) {
// splitText(), aInfo->mDetails->mNextSibling is the new text node
NS_ASSERTION(aInfo->mDetails->mType ==
CharacterDataChangeInfo::Details::eSplit,
"only a split can start before the end");
- NS_ASSERTION(static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd + 1,
+ NS_ASSERTION(mStartOffset <= aInfo->mChangeEnd + 1,
"mStartOffset is beyond the end of this node");
- newStartOffset = static_cast<uint32_t>(mStartOffset) - aInfo->mChangeStart;
+ newStartOffset = mStartOffset - aInfo->mChangeStart;
newStartNode = aInfo->mDetails->mNextSibling;
if (MOZ_UNLIKELY(aContent == mRoot)) {
newRoot = IsValidBoundary(newStartNode);
@@ -512,7 +529,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
} else {
// If boundary is inside changed text, position it before change
// else adjust start offset for the change in length.
- mStartOffset = static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd ?
+ mStartOffset = mStartOffset <= aInfo->mChangeEnd ?
aInfo->mChangeStart :
mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
aInfo->mReplaceLength;
@@ -522,16 +539,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// Do the same thing for the end boundary, except for splitText of a node
// with no parent then only switch to the new node if the start boundary
// did so too (otherwise the range would end up with disconnected nodes).
- if (aContent == mEndParent &&
- aInfo->mChangeStart < static_cast<uint32_t>(mEndOffset)) {
+ if (aContent == mEndParent && aInfo->mChangeStart < mEndOffset) {
if (aInfo->mDetails && (aContent->GetParentNode() || newStartNode)) {
// splitText(), aInfo->mDetails->mNextSibling is the new text node
NS_ASSERTION(aInfo->mDetails->mType ==
CharacterDataChangeInfo::Details::eSplit,
"only a split can start before the end");
- NS_ASSERTION(static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd + 1,
+ NS_ASSERTION(mEndOffset <= aInfo->mChangeEnd + 1,
"mEndOffset is beyond the end of this node");
- newEndOffset = static_cast<uint32_t>(mEndOffset) - aInfo->mChangeStart;
+ newEndOffset = mEndOffset - aInfo->mChangeStart;
newEndNode = aInfo->mDetails->mNextSibling;
bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
@@ -544,7 +560,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
}
} else {
- mEndOffset = static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd ?
+ mEndOffset = mEndOffset <= aInfo->mChangeEnd ?
aInfo->mChangeStart :
mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
aInfo->mReplaceLength;
@@ -557,14 +573,14 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// that will be removed
nsIContent* removed = aInfo->mDetails->mNextSibling;
if (removed == mStartParent) {
- newStartOffset = static_cast<uint32_t>(mStartOffset) + aInfo->mChangeStart;
+ newStartOffset = mStartOffset + aInfo->mChangeStart;
newStartNode = aContent;
if (MOZ_UNLIKELY(removed == mRoot)) {
newRoot = IsValidBoundary(newStartNode);
}
}
if (removed == mEndParent) {
- newEndOffset = static_cast<uint32_t>(mEndOffset) + aInfo->mChangeStart;
+ newEndOffset = mEndOffset + aInfo->mChangeStart;
newEndNode = aContent;
if (MOZ_UNLIKELY(removed == mRoot)) {
newRoot = IsValidBoundary(newEndNode);
@@ -578,13 +594,13 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// point before the first child is never affected by normalize().)
nsINode* parentNode = aContent->GetParentNode();
if (parentNode == mStartParent && mStartOffset > 0 &&
- uint32_t(mStartOffset) < parentNode->GetChildCount() &&
+ mStartOffset < parentNode->GetChildCount() &&
removed == parentNode->GetChildAt(mStartOffset)) {
newStartNode = aContent;
newStartOffset = aInfo->mChangeStart;
}
if (parentNode == mEndParent && mEndOffset > 0 &&
- uint32_t(mEndOffset) < parentNode->GetChildCount() &&
+ mEndOffset < parentNode->GetChildCount() &&
removed == parentNode->GetChildAt(mEndOffset)) {
newEndNode = aContent;
newEndOffset = aInfo->mChangeEnd;
@@ -649,13 +665,19 @@ nsRange::ContentInserted(nsIDocument* aDocument,
nsINode* container = NODE_FROM(aContainer, aDocument);
// Adjust position if a sibling was inserted.
- if (container == mStartParent && aIndexInContainer < mStartOffset &&
+ if (container == mStartParent &&
+ (NS_WARN_IF(aIndexInContainer < 0) ||
+ static_cast<uint32_t>(aIndexInContainer) < mStartOffset) &&
!mStartOffsetWasIncremented) {
++mStartOffset;
+ MOZ_ASSERT(IsValidOffset(mStartOffset));
}
- if (container == mEndParent && aIndexInContainer < mEndOffset &&
+ if (container == mEndParent &&
+ (NS_WARN_IF(aIndexInContainer < 0) ||
+ static_cast<uint32_t>(aIndexInContainer) < mEndOffset) &&
!mEndOffsetWasIncremented) {
++mEndOffset;
+ MOZ_ASSERT(IsValidOffset(mEndOffset));
}
if (container->IsSelectionDescendant() &&
!aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
@@ -694,7 +716,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
// Adjust position if a sibling was removed...
if (container == mStartParent) {
- if (aIndexInContainer < mStartOffset) {
+ if (aIndexInContainer < static_cast<int32_t>(mStartOffset)) {
--mStartOffset;
}
} else { // ...or gravitate if an ancestor was removed.
@@ -704,7 +726,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
// Do same thing for end boundry.
if (container == mEndParent) {
- if (aIndexInContainer < mEndOffset) {
+ if (aIndexInContainer < static_cast<int32_t>(mEndOffset)) {
--mEndOffset;
}
} else if (didCheckStartParentDescendant && mStartParent == mEndParent) {
@@ -763,12 +785,15 @@ nsRange::ParentChainChanged(nsIContent *aContent)
* Utilities for comparing points: API from nsIDOMRange
******************************************************/
NS_IMETHODIMP
-nsRange::IsPointInRange(nsIDOMNode* aParent, int32_t aOffset, bool* aResult)
+nsRange::IsPointInRange(nsIDOMNode* aParent, uint32_t aOffset, bool* aResult)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
if (!parent) {
return NS_ERROR_DOM_NOT_OBJECT_ERR;
}
+ if (NS_WARN_IF(!IsValidOffset(aOffset))) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
ErrorResult rv;
*aResult = IsPointInRange(*parent, aOffset, rv);
@@ -791,7 +816,7 @@ nsRange::IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
// returns -1 if point is before range, 0 if point is in range,
// 1 if point is after range.
NS_IMETHODIMP
-nsRange::ComparePoint(nsIDOMNode* aParent, int32_t aOffset, int16_t* aResult)
+nsRange::ComparePoint(nsIDOMNode* aParent, uint32_t aOffset, int16_t* aResult)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
NS_ENSURE_TRUE(parent, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
@@ -825,14 +850,18 @@ nsRange::ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
return 0;
}
- int32_t cmp;
- if ((cmp = nsContentUtils::ComparePoints(&aParent, aOffset,
- mStartParent, mStartOffset)) <= 0) {
-
+ int32_t cmp =
+ nsContentUtils::ComparePoints(&aParent,
+ static_cast<int32_t>(aOffset),
+ mStartParent,
+ static_cast<int32_t>(mStartOffset));
+ if (cmp <= 0) {
return cmp;
}
- if (nsContentUtils::ComparePoints(mEndParent, mEndOffset,
- &aParent, aOffset) == -1) {
+ if (nsContentUtils::ComparePoints(mEndParent,
+ static_cast<int32_t>(mEndOffset),
+ &aParent,
+ static_cast<int32_t>(aOffset)) == -1) {
return 1;
}
@@ -875,12 +904,15 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
// Steps 6-7.
// Note: if disconnected is true, ComparePoints returns 1.
bool disconnected = false;
- bool result = nsContentUtils::ComparePoints(mStartParent, mStartOffset,
- parent, nodeIndex + 1,
- &disconnected) < 0 &&
- nsContentUtils::ComparePoints(parent, nodeIndex,
- mEndParent, mEndOffset,
- &disconnected) < 0;
+ bool result =
+ nsContentUtils::ComparePoints(mStartParent,
+ static_cast<int32_t>(mStartOffset),
+ parent, nodeIndex + 1,
+ &disconnected) < 0 &&
+ nsContentUtils::ComparePoints(parent, nodeIndex,
+ mEndParent,
+ static_cast<int32_t>(mEndOffset),
+ &disconnected) < 0;
// Step 2.
if (disconnected) {
@@ -899,8 +931,8 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
// Calling DoSetRange with either parent argument null will collapse
// the range to have both endpoints point to the other node
void
-nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
- nsINode* aEndN, int32_t aEndOffset,
+nsRange::DoSetRange(nsINode* aStartN, uint32_t aStartOffset,
+ nsINode* aEndN, uint32_t aEndOffset,
nsINode* aRoot, bool aNotInsertedYet)
{
NS_PRECONDITION((aStartN && aEndN && aRoot) ||
@@ -926,6 +958,8 @@ nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
/*For backward compatibility*/
aRoot->IsNodeOfType(nsINode::eCONTENT))),
"Bad root");
+ MOZ_ASSERT(IsValidOffset(aStartOffset));
+ MOZ_ASSERT(IsValidOffset(aEndOffset));
if (mRoot != aRoot) {
if (mRoot) {
@@ -1038,7 +1072,7 @@ nsRange::GetStartContainer(ErrorResult& aRv) const
}
NS_IMETHODIMP
-nsRange::GetStartOffset(int32_t* aStartOffset)
+nsRange::GetStartOffset(uint32_t* aStartOffset)
{
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@@ -1080,7 +1114,7 @@ nsRange::GetEndContainer(ErrorResult& aRv) const
}
NS_IMETHODIMP
-nsRange::GetEndOffset(int32_t* aEndOffset)
+nsRange::GetEndOffset(uint32_t* aEndOffset)
{
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@@ -1137,6 +1171,15 @@ nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
return rv.StealNSResult();
}
+/* static */
+bool
+nsRange::IsValidOffset(nsINode* aNode, uint32_t aOffset)
+{
+ return aNode &&
+ IsValidOffset(aOffset) &&
+ static_cast<size_t>(aOffset) <= aNode->Length();
+}
+
nsINode*
nsRange::IsValidBoundary(nsINode* aNode)
{
@@ -1197,7 +1240,7 @@ nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
}
NS_IMETHODIMP
-nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
+nsRange::SetStart(nsIDOMNode* aParent, uint32_t aOffset)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
if (!parent) {
@@ -1210,22 +1253,24 @@ nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
}
/* virtual */ nsresult
-nsRange::SetStart(nsINode* aParent, int32_t aOffset)
+nsRange::SetStart(nsINode* aParent, uint32_t aOffset)
{
nsINode* newRoot = IsValidBoundary(aParent);
if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
- if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
+ if (!IsValidOffset(aParent, aOffset)) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Collapse if not positioned yet, if positioned in another doc or
// if the new start is after end.
if (!mIsPositioned || newRoot != mRoot ||
- nsContentUtils::ComparePoints(aParent, aOffset,
- mEndParent, mEndOffset) == 1) {
+ nsContentUtils::ComparePoints(aParent,
+ static_cast<int32_t>(aOffset),
+ mEndParent,
+ static_cast<int32_t>(mEndOffset)) == 1) {
DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
return NS_OK;
@@ -1246,7 +1291,12 @@ nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode));
+ // If the node is being removed from its parent, GetContainerAndOffsetBefore()
+ // returns nullptr. Then, SetStart() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
+ aRv = SetStart(parent, offset);
}
NS_IMETHODIMP
@@ -1272,7 +1322,12 @@ nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1);
+ // If the node is being removed from its parent, GetContainerAndOffsetAfter()
+ // returns nullptr. Then, SetStart() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
+ aRv = SetStart(parent, offset);
}
NS_IMETHODIMP
@@ -1301,7 +1356,7 @@ nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
}
NS_IMETHODIMP
-nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
+nsRange::SetEnd(nsIDOMNode* aParent, uint32_t aOffset)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
if (!parent) {
@@ -1314,22 +1369,24 @@ nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
}
/* virtual */ nsresult
-nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
+nsRange::SetEnd(nsINode* aParent, uint32_t aOffset)
{
nsINode* newRoot = IsValidBoundary(aParent);
if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
- if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
+ if (!IsValidOffset(aParent, aOffset)) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Collapse if not positioned yet, if positioned in another doc or
// if the new end is before start.
if (!mIsPositioned || newRoot != mRoot ||
- nsContentUtils::ComparePoints(mStartParent, mStartOffset,
- aParent, aOffset) == 1) {
+ nsContentUtils::ComparePoints(mStartParent,
+ static_cast<int32_t>(mStartOffset),
+ aParent,
+ static_cast<int32_t>(aOffset)) == 1) {
DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
return NS_OK;
@@ -1340,6 +1397,66 @@ nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
return NS_OK;
}
+nsresult
+nsRange::SetStartAndEnd(nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset)
+{
+ if (NS_WARN_IF(!aStartParent) || NS_WARN_IF(!aEndParent)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsINode* newStartRoot = IsValidBoundary(aStartParent);
+ if (!newStartRoot) {
+ return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+ }
+ if (!IsValidOffset(aStartParent, aStartOffset)) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
+
+ if (aStartParent == aEndParent) {
+ if (!IsValidOffset(aEndParent, aEndOffset)) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
+ // If the end offset is less than the start offset, this should be
+ // collapsed at the end offset.
+ if (aStartOffset > aEndOffset) {
+ DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newStartRoot);
+ } else {
+ DoSetRange(aStartParent, aStartOffset,
+ aEndParent, aEndOffset, newStartRoot);
+ }
+ return NS_OK;
+ }
+
+ nsINode* newEndRoot = IsValidBoundary(aEndParent);
+ if (!newEndRoot) {
+ return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+ }
+ if (!IsValidOffset(aEndParent, aEndOffset)) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
+
+ // If they have different root, this should be collapsed at the end point.
+ if (newStartRoot != newEndRoot) {
+ DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
+ return NS_OK;
+ }
+
+ // If the end point is before the start point, this should be collapsed at
+ // the end point.
+ if (nsContentUtils::ComparePoints(aStartParent,
+ static_cast<int32_t>(aStartOffset),
+ aEndParent,
+ static_cast<int32_t>(aEndOffset)) == 1) {
+ DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
+ return NS_OK;
+ }
+
+ // Otherwise, set the range as specified.
+ DoSetRange(aStartParent, aStartOffset, aEndParent, aEndOffset, newStartRoot);
+ return NS_OK;
+}
+
void
nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
{
@@ -1350,7 +1467,12 @@ nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode));
+ // If the node is being removed from its parent, GetContainerAndOffsetBefore()
+ // returns nullptr. Then, SetEnd() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
+ aRv = SetEnd(parent, offset);
}
NS_IMETHODIMP
@@ -1376,7 +1498,12 @@ nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1);
+ // If the node is being removed from its parent, GetContainerAndOffsetAfter()
+ // returns nullptr. Then, SetEnd() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
+ aRv = SetEnd(parent, offset);
}
NS_IMETHODIMP
@@ -1435,7 +1562,9 @@ nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
}
int32_t index = parent->IndexOf(&aNode);
- if (index < 0) {
+ if (NS_WARN_IF(index < 0) ||
+ !IsValidOffset(static_cast<uint32_t>(index)) ||
+ !IsValidOffset(static_cast<uint32_t>(index) + 1)) {
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return;
}
@@ -1884,9 +2013,9 @@ nsRange::CutContents(DocumentFragment** aFragment)
// of Range gravity during our edits!
nsCOMPtr<nsINode> startContainer = mStartParent;
- int32_t startOffset = mStartOffset;
+ uint32_t startOffset = mStartOffset;
nsCOMPtr<nsINode> endContainer = mEndParent;
- int32_t endOffset = mEndOffset;
+ uint32_t endOffset = mEndOffset;
if (retval) {
// For extractContents(), abort early if there's a doctype (bug 719533).
@@ -1897,10 +2026,12 @@ nsRange::CutContents(DocumentFragment** aFragment)
RefPtr<DocumentType> doctype = commonAncestorDocument->GetDoctype();
if (doctype &&
- nsContentUtils::ComparePoints(startContainer, startOffset,
+ nsContentUtils::ComparePoints(startContainer,
+ static_cast<int32_t>(startOffset),
doctype, 0) < 0 &&
nsContentUtils::ComparePoints(doctype, 0,
- endContainer, endOffset) < 0) {
+ endContainer,
+ static_cast<int32_t>(endOffset)) < 0) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
}
@@ -1995,8 +2126,7 @@ nsRange::CutContents(DocumentFragment** aFragment)
rv = charData->GetLength(&dataLength);
NS_ENSURE_SUCCESS(rv, rv);
- if (dataLength >= (uint32_t)startOffset)
- {
+ if (dataLength >= startOffset) {
nsMutationGuard guard;
nsCOMPtr<nsIDOMCharacterData> cutNode;
rv = SplitDataNode(charData, startOffset, getter_AddRefs(cutNode));
@@ -2012,22 +2142,17 @@ nsRange::CutContents(DocumentFragment** aFragment)
else if (node == endContainer)
{
// Delete or extract everything before endOffset.
-
- if (endOffset >= 0)
- {
- nsMutationGuard guard;
- nsCOMPtr<nsIDOMCharacterData> cutNode;
- /* The Range spec clearly states clones get cut and original nodes
- remain behind, so use false as the last parameter.
- */
- rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
- false);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_STATE(!guard.Mutated(1) ||
- ValidateCurrentNode(this, iter));
- nodeToResult = do_QueryInterface(cutNode);
- }
-
+ nsMutationGuard guard;
+ nsCOMPtr<nsIDOMCharacterData> cutNode;
+ /* The Range spec clearly states clones get cut and original nodes
+ remain behind, so use false as the last parameter.
+ */
+ rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
+ false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_STATE(!guard.Mutated(1) ||
+ ValidateCurrentNode(this, iter));
+ nodeToResult = do_QueryInterface(cutNode);
handled = true;
}
}
@@ -2037,8 +2162,7 @@ nsRange::CutContents(DocumentFragment** aFragment)
if (node && node->IsElement() &&
((node == endContainer && endOffset == 0) ||
(node == startContainer &&
- int32_t(node->AsElement()->GetChildCount()) == startOffset)))
- {
+ node->AsElement()->GetChildCount() == startOffset))) {
if (retval) {
ErrorResult rv;
nodeToResult = node->CloneNode(false, rv);
@@ -2183,7 +2307,7 @@ nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
}
nsINode *ourNode, *otherNode;
- int32_t ourOffset, otherOffset;
+ uint32_t ourOffset, otherOffset;
switch (aHow) {
case nsIDOMRange::START_TO_START:
@@ -2221,8 +2345,10 @@ nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
return 0;
}
- return nsContentUtils::ComparePoints(ourNode, ourOffset,
- otherNode, otherOffset);
+ return nsContentUtils::ComparePoints(ourNode,
+ static_cast<int32_t>(ourOffset),
+ otherNode,
+ static_cast<int32_t>(otherOffset));
}
/* static */ nsresult
@@ -2339,8 +2465,7 @@ nsRange::CloneContents(ErrorResult& aRv)
bool deepClone = !node->IsElement() ||
(!(node == mEndParent && mEndOffset == 0) &&
!(node == mStartParent &&
- mStartOffset ==
- int32_t(node->AsElement()->GetChildCount())));
+ mStartOffset == node->AsElement()->GetChildCount()));
// Clone the current subtree!
@@ -2370,7 +2495,7 @@ nsRange::CloneContents(ErrorResult& aRv)
return nullptr;
}
- if (dataLength > (uint32_t)mEndOffset)
+ if (dataLength > mEndOffset)
{
aRv = charData->DeleteData(mEndOffset, dataLength - mEndOffset);
if (aRv.Failed()) {
@@ -2528,7 +2653,7 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
return;
}
- int32_t tStartOffset = StartOffset();
+ uint32_t tStartOffset = StartOffset();
nsCOMPtr<nsINode> tStartContainer = GetStartContainer(aRv);
if (aRv.Failed()) {
@@ -2589,18 +2714,20 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
// We might need to update the end to include the new node (bug 433662).
// Ideally we'd only do this if needed, but it's tricky to know when it's
// needed in advance (bug 765799).
- int32_t newOffset;
+ uint32_t newOffset;
if (referenceNode) {
- newOffset = IndexOf(referenceNode);
+ int32_t indexInParent = IndexOf(referenceNode);
+ if (NS_WARN_IF(indexInParent < 0)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+ newOffset = static_cast<uint32_t>(indexInParent);
} else {
- uint32_t length;
- aRv = tChildList->GetLength(&length);
+ aRv = tChildList->GetLength(&newOffset);
if (aRv.Failed()) {
return;
}
-
- newOffset = length;
}
if (aNode.NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
@@ -2956,10 +3083,15 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
mozilla::dom::DOMStringList* aTextList,
nsRange* aRange,
- nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset,
+ nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset,
bool aClampToEdge, bool aFlushLayout)
{
+ // Currently, this method is called with start of end offset of nsRange.
+ // So, they must be between 0 - INT32_MAX.
+ MOZ_ASSERT(IsValidOffset(aStartOffset));
+ MOZ_ASSERT(IsValidOffset(aEndOffset));
+
// Hold strong pointers across the flush
nsCOMPtr<nsINode> startContainer = aStartParent;
nsCOMPtr<nsINode> endContainer = aEndParent;
@@ -2990,13 +3122,15 @@ nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
if (textFrame) {
int32_t outOffset;
nsIFrame* outFrame;
- textFrame->GetChildFrameContainingOffset(aStartOffset, false,
- &outOffset, &outFrame);
+ textFrame->GetChildFrameContainingOffset(
+ static_cast<int32_t>(aStartOffset), false,
+ &outOffset, &outFrame);
if (outFrame) {
nsIFrame* relativeTo =
nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
nsRect r = outFrame->GetRectRelativeToSelf();
- ExtractRectFromOffset(outFrame, aStartOffset, &r, false, aClampToEdge);
+ ExtractRectFromOffset(outFrame, static_cast<int32_t>(aStartOffset),
+ &r, false, aClampToEdge);
r.width = 0;
r = nsLayoutUtils::TransformFrameRectToAncestor(outFrame, r, relativeTo);
aCollector->AddRect(r);
@@ -3015,12 +3149,14 @@ nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
if (content->IsNodeOfType(nsINode::eTEXT)) {
if (node == startContainer) {
int32_t offset = startContainer == endContainer ?
- aEndOffset : content->GetText()->GetLength();
- GetPartialTextRect(aCollector, aTextList, content, aStartOffset, offset,
+ static_cast<int32_t>(aEndOffset) : content->GetText()->GetLength();
+ GetPartialTextRect(aCollector, aTextList, content,
+ static_cast<int32_t>(aStartOffset), offset,
aClampToEdge, aFlushLayout);
continue;
} else if (node == endContainer) {
- GetPartialTextRect(aCollector, aTextList, content, 0, aEndOffset,
+ GetPartialTextRect(aCollector, aTextList, content,
+ 0, static_cast<int32_t>(aEndOffset),
aClampToEdge, aFlushLayout);
continue;
}
@@ -3397,7 +3533,7 @@ ElementIsVisibleNoFlush(Element* aElement)
static void
AppendTransformedText(InnerTextAccumulator& aResult,
nsGenericDOMDataNode* aTextNode,
- int32_t aStart, int32_t aEnd)
+ uint32_t aStart, uint32_t aEnd)
{
nsIFrame* frame = aTextNode->GetPrimaryFrame();
if (!IsVisibleAndNotInReplacedElement(frame)) {
@@ -3506,7 +3642,7 @@ nsRange::GetInnerTextNoFlush(DOMString& aValue, ErrorResult& aError,
if (aEndParent->IsNodeOfType(nsINode::eTEXT)) {
endState = AT_NODE;
} else {
- if (uint32_t(aEndOffset) < aEndParent->GetChildCount()) {
+ if (aEndOffset < aEndParent->GetChildCount()) {
endNode = aEndParent->GetChildAt(aEndOffset);
endState = AT_NODE;
}