diff options
Diffstat (limited to 'dom/base/nsRange.cpp')
-rw-r--r-- | dom/base/nsRange.cpp | 121 |
1 files changed, 93 insertions, 28 deletions
diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index d45a2c975..154b3428f 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -270,14 +270,17 @@ nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset, nsINode* aEndParent, int32_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 */ @@ -286,22 +289,9 @@ nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset, nsIDOMNode* aEndParent, int32_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 */ @@ -1137,6 +1127,15 @@ nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent) return rv.StealNSResult(); } +/* static */ +bool +nsRange::IsValidOffset(nsINode* aNode, int32_t aOffset) +{ + return aNode && + aOffset >= 0 && + static_cast<size_t>(aOffset) <= aNode->Length(); +} + nsINode* nsRange::IsValidBoundary(nsINode* aNode) { @@ -1217,7 +1216,7 @@ nsRange::SetStart(nsINode* aParent, int32_t aOffset) 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; } @@ -1246,7 +1245,9 @@ nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv) } AutoInvalidateSelection atEndOfBlock(this); - aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode)); + int32_t offset = -1; + nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset); + aRv = SetStart(parent, offset); } NS_IMETHODIMP @@ -1272,7 +1273,9 @@ nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv) } AutoInvalidateSelection atEndOfBlock(this); - aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1); + int32_t offset = -1; + nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset); + aRv = SetStart(parent, offset); } NS_IMETHODIMP @@ -1321,7 +1324,7 @@ nsRange::SetEnd(nsINode* aParent, int32_t aOffset) 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; } @@ -1340,6 +1343,64 @@ nsRange::SetEnd(nsINode* aParent, int32_t aOffset) return NS_OK; } +nsresult +nsRange::SetStartAndEnd(nsINode* aStartParent, int32_t aStartOffset, + nsINode* aEndParent, int32_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, aStartOffset, + aEndParent, 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 +1411,9 @@ nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv) } AutoInvalidateSelection atEndOfBlock(this); - aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode)); + int32_t offset = -1; + nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset); + aRv = SetEnd(parent, offset); } NS_IMETHODIMP @@ -1376,7 +1439,9 @@ nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv) } AutoInvalidateSelection atEndOfBlock(this); - aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1); + int32_t offset = -1; + nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset); + aRv = SetEnd(parent, offset); } NS_IMETHODIMP |