Bug 1423097 - part 2: Add overloads of nsRange::SetStart(), nsRange::SetEnd(), nsRange::IsPointInRange() and nsRange::ComparePoint() to use them with RawRangeBoundary r=smaug

nsRange::SetStart(), nsRange::SetEnd(), nsRange::IsPointInRange() and
nsRange::ComparePoint() take a set of container node and offset in it to
specifying a DOM point.  However, the caller may not have computed the offset
but may know the child node at the point.  In such case, they can avoid
computing the offset with nsINode::IndexOf() if they have overloads which
take RawRangeBoundary.

Therefore, this patch implements the overloads and changes the callers in
editor.

MozReview-Commit-ID: E4DLbAgTTCI

--HG--
extra : rebase_source : 8d1632a030f1e0a0dd2b81c3996c19d427e8b0bd
This commit is contained in:
Masayuki Nakano 2017-12-05 17:50:13 +09:00
Родитель 0021ffcddf
Коммит bab72d08e8
3 изменённых файлов: 105 добавлений и 92 удалений

Просмотреть файл

@ -285,7 +285,7 @@ nsRange::~nsRange()
NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use"); NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
// we want the side effects (releases and list removals) // we want the side effects (releases and list removals)
DoSetRange(nullptr, 0, nullptr, 0, nullptr); DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr);
} }
nsRange::nsRange(nsINode* aNode) nsRange::nsRange(nsINode* aNode)
@ -859,14 +859,14 @@ nsRange::IsPointInRange(nsIDOMNode* aContainer, uint32_t aOffset, bool* aResult)
} }
ErrorResult rv; ErrorResult rv;
*aResult = IsPointInRange(*container, aOffset, rv); *aResult = IsPointInRange(RawRangeBoundary(container, aOffset), rv);
return rv.StealNSResult(); return rv.StealNSResult();
} }
bool bool
nsRange::IsPointInRange(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv) nsRange::IsPointInRange(const RawRangeBoundary& aPoint, ErrorResult& aRv)
{ {
uint16_t compareResult = ComparePoint(aContainer, aOffset, aRv); uint16_t compareResult = ComparePoint(aPoint, aRv);
// If the node isn't in the range's document, it clearly isn't in the range. // If the node isn't in the range's document, it clearly isn't in the range.
if (aRv.ErrorCodeIs(NS_ERROR_DOM_WRONG_DOCUMENT_ERR)) { if (aRv.ErrorCodeIs(NS_ERROR_DOM_WRONG_DOCUMENT_ERR)) {
aRv.SuppressException(); aRv.SuppressException();
@ -886,42 +886,46 @@ nsRange::ComparePoint(nsIDOMNode* aContainer, uint32_t aOffset,
NS_ENSURE_TRUE(container, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); NS_ENSURE_TRUE(container, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
ErrorResult rv; ErrorResult rv;
*aResult = ComparePoint(*container, aOffset, rv); *aResult = ComparePoint(RawRangeBoundary(container, aOffset), rv);
return rv.StealNSResult(); return rv.StealNSResult();
} }
int16_t int16_t
nsRange::ComparePoint(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv) nsRange::ComparePoint(const RawRangeBoundary& aPoint, ErrorResult& aRv)
{ {
if (NS_WARN_IF(!aPoint.IsSet())) {
// FYI: Shouldn't reach this case if it's called by JS. Therefore, it's
// okay to warn.
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return 0;
}
// our range is in a good state? // our range is in a good state?
if (!mIsPositioned) { if (!mIsPositioned) {
aRv.Throw(NS_ERROR_NOT_INITIALIZED); aRv.Throw(NS_ERROR_NOT_INITIALIZED);
return 0; return 0;
} }
if (!nsContentUtils::ContentIsDescendantOf(&aContainer, mRoot)) { if (!nsContentUtils::ContentIsDescendantOf(aPoint.Container(), mRoot)) {
aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
return 0; return 0;
} }
if (aContainer.NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { if (aPoint.Container()->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return 0; return 0;
} }
if (aOffset > aContainer.Length()) { if (aPoint.Offset() > aPoint.Container()->Length()) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return 0; return 0;
} }
int32_t cmp = nsContentUtils::ComparePoints(&aContainer, aOffset, int32_t cmp = nsContentUtils::ComparePoints(aPoint, mStart.AsRaw());
mStart.Container(),
mStart.Offset());
if (cmp <= 0) { if (cmp <= 0) {
return cmp; return cmp;
} }
if (nsContentUtils::ComparePoints(mEnd.Container(), mEnd.Offset(), if (nsContentUtils::ComparePoints(mEnd.AsRaw(), aPoint) == -1) {
&aContainer, aOffset) == -1) {
return 1; return 1;
} }
@ -1378,7 +1382,7 @@ nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
} }
AutoInvalidateSelection atEndOfBlock(this); AutoInvalidateSelection atEndOfBlock(this);
aRv = SetStart(&aNode, aOffset); SetStart(RawRangeBoundary(&aNode, aOffset), aRv);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1394,33 +1398,29 @@ nsRange::SetStart(nsIDOMNode* aContainer, uint32_t aOffset)
return rv.StealNSResult(); return rv.StealNSResult();
} }
/* virtual */ nsresult void
nsRange::SetStart(nsINode* aContainer, uint32_t aOffset) nsRange::SetStart(const RawRangeBoundary& aPoint, ErrorResult& aRv)
{ {
nsINode* newRoot = IsValidBoundary(aContainer); nsINode* newRoot = IsValidBoundary(aPoint.Container());
if (!newRoot) { if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return;
} }
if (!IsValidOffset(aContainer, aOffset)) { if (!aPoint.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR; aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
} }
// Collapse if not positioned yet, if positioned in another doc or // Collapse if not positioned yet, if positioned in another doc or
// if the new start is after end. // if the new start is after end.
if (!mIsPositioned || newRoot != mRoot || if (!mIsPositioned || newRoot != mRoot ||
nsContentUtils::ComparePoints(aContainer, nsContentUtils::ComparePoints(aPoint, mEnd.AsRaw()) == 1) {
static_cast<int32_t>(aOffset), DoSetRange(aPoint, aPoint, newRoot);
mEnd.Container(), mEnd.Offset()) == 1) { return;
DoSetRange(aContainer, aOffset, aContainer, aOffset, newRoot);
return NS_OK;
} }
RawRangeBoundary newStart(aContainer, aOffset); DoSetRange(aPoint, mEnd.AsRaw(), mRoot);
DoSetRange(newStart, mEnd.AsRaw(), mRoot);
return NS_OK;
} }
void void
@ -1518,7 +1518,7 @@ nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
return; return;
} }
AutoInvalidateSelection atEndOfBlock(this); AutoInvalidateSelection atEndOfBlock(this);
aRv = SetEnd(&aNode, aOffset); SetEnd(RawRangeBoundary(&aNode, aOffset), aRv);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1534,34 +1534,29 @@ nsRange::SetEnd(nsIDOMNode* aContainer, uint32_t aOffset)
return rv.StealNSResult(); return rv.StealNSResult();
} }
/* virtual */ nsresult void
nsRange::SetEnd(nsINode* aContainer, uint32_t aOffset) nsRange::SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aRv)
{ {
nsINode* newRoot = IsValidBoundary(aContainer); nsINode* newRoot = IsValidBoundary(aPoint.Container());
if (!newRoot) { if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return;
} }
if (!IsValidOffset(aContainer, aOffset)) { if (!aPoint.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR; aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
} }
// Collapse if not positioned yet, if positioned in another doc or // Collapse if not positioned yet, if positioned in another doc or
// if the new end is before start. // if the new end is before start.
if (!mIsPositioned || newRoot != mRoot || if (!mIsPositioned || newRoot != mRoot ||
nsContentUtils::ComparePoints(mStart.Container(), nsContentUtils::ComparePoints(mStart.AsRaw(), aPoint) == 1) {
static_cast<int32_t>(mStart.Offset()), DoSetRange(aPoint, aPoint, newRoot);
aContainer, return;
static_cast<int32_t>(aOffset)) == 1) {
DoSetRange(aContainer, aOffset, aContainer, aOffset, newRoot);
return NS_OK;
} }
RawRangeBoundary newEnd(aContainer, aOffset); DoSetRange(mStart.AsRaw(), aPoint, mRoot);
DoSetRange(mStart.AsRaw(), newEnd, mRoot);
return NS_OK;
} }
void void
@ -1642,18 +1637,6 @@ nsRange::SetStartAndEnd(const RawRangeBoundary& aStart,
return NS_OK; return NS_OK;
} }
nsresult
nsRange::SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
nsINode* aEndContainer, uint32_t aEndOffset)
{
if (NS_WARN_IF(!aStartContainer) || NS_WARN_IF(!aEndContainer)) {
return NS_ERROR_INVALID_ARG;
}
return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
RawRangeBoundary(aEndContainer, aEndOffset));
}
void void
nsRange::SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr) nsRange::SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr)
{ {
@ -1804,7 +1787,8 @@ nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
} }
AutoInvalidateSelection atEndOfBlock(this); AutoInvalidateSelection atEndOfBlock(this);
DoSetRange(container, index, container, index + 1, newRoot); DoSetRange(RawRangeBoundary(container, index),
RawRangeBoundary(container, index + 1), newRoot);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1842,7 +1826,8 @@ nsRange::SelectNodeContents(nsINode& aNode, ErrorResult& aRv)
} }
AutoInvalidateSelection atEndOfBlock(this); AutoInvalidateSelection atEndOfBlock(this);
DoSetRange(&aNode, 0, &aNode, aNode.Length(), newRoot); DoSetRange(RawRangeBoundary(&aNode, 0),
RawRangeBoundary(&aNode, aNode.Length()), newRoot);
} }
// The Subtree Content Iterator only returns subtrees that are // The Subtree Content Iterator only returns subtrees that are

Просмотреть файл

@ -182,8 +182,18 @@ public:
* When you set both start and end of a range, you should use * When you set both start and end of a range, you should use
* SetStartAndEnd() instead. * SetStartAndEnd() instead.
*/ */
nsresult SetStart(nsINode* aContainer, uint32_t aOffset); nsresult SetStart(nsINode* aContainer, uint32_t aOffset)
nsresult SetEnd(nsINode* aContainer, uint32_t aOffset); {
ErrorResult error;
SetStart(RawRangeBoundary(aContainer, aOffset), error);
return error.StealNSResult();
}
nsresult SetEnd(nsINode* aContainer, uint32_t aOffset)
{
ErrorResult error;
SetEnd(RawRangeBoundary(aContainer, aOffset), error);
return error.StealNSResult();
}
already_AddRefed<nsRange> CloneRange() const; already_AddRefed<nsRange> CloneRange() const;
@ -196,7 +206,11 @@ public:
* the range will be collapsed at the end point. * the range will be collapsed at the end point.
*/ */
nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset, nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
nsINode* aEndContainer, uint32_t aEndOffset); nsINode* aEndContainer, uint32_t aEndOffset)
{
return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
RawRangeBoundary(aEndContainer, aEndOffset));
}
nsresult SetStartAndEnd(const RawRangeBoundary& aStart, nsresult SetStartAndEnd(const RawRangeBoundary& aStart,
const RawRangeBoundary& aEnd); const RawRangeBoundary& aEnd);
@ -290,7 +304,11 @@ public:
int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther, int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther,
ErrorResult& aErr); ErrorResult& aErr);
int16_t ComparePoint(nsINode& aContainer, uint32_t aOffset, int16_t ComparePoint(nsINode& aContainer, uint32_t aOffset,
ErrorResult& aErr); ErrorResult& aErr)
{
return ComparePoint(RawRangeBoundary(&aContainer, aOffset), aErr);
}
int16_t ComparePoint(const RawRangeBoundary& aPoint, ErrorResult& aErr);
void DeleteContents(ErrorResult& aRv); void DeleteContents(ErrorResult& aRv);
already_AddRefed<mozilla::dom::DocumentFragment> already_AddRefed<mozilla::dom::DocumentFragment>
ExtractContents(ErrorResult& aErr); ExtractContents(ErrorResult& aErr);
@ -301,7 +319,11 @@ public:
uint32_t GetEndOffset(ErrorResult& aRv) const; uint32_t GetEndOffset(ErrorResult& aRv) const;
void InsertNode(nsINode& aNode, ErrorResult& aErr); void InsertNode(nsINode& aNode, ErrorResult& aErr);
bool IntersectsNode(nsINode& aNode, ErrorResult& aRv); bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
bool IsPointInRange(nsINode& aContainer, uint32_t aOffset, ErrorResult& aErr); bool IsPointInRange(nsINode& aContainer, uint32_t aOffset, ErrorResult& aErr)
{
return IsPointInRange(RawRangeBoundary(&aContainer, aOffset), aErr);
}
bool IsPointInRange(const RawRangeBoundary& aPoint, ErrorResult& aErr);
// *JS() methods are mapped to Range.*() of DOM. // *JS() methods are mapped to Range.*() of DOM.
// They may move focus only when the range represents normal selection. // They may move focus only when the range represents normal selection.
@ -329,9 +351,11 @@ public:
void SelectNode(nsINode& aNode, ErrorResult& aErr); void SelectNode(nsINode& aNode, ErrorResult& aErr);
void SelectNodeContents(nsINode& aNode, ErrorResult& aErr); void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr); void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
void SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aErr);
void SetEndAfter(nsINode& aNode, ErrorResult& aErr); void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
void SetEndBefore(nsINode& aNode, ErrorResult& aErr); void SetEndBefore(nsINode& aNode, ErrorResult& aErr);
void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr); void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
void SetStart(const RawRangeBoundary& aPoint, ErrorResult& aErr);
void SetStartAfter(nsINode& aNode, ErrorResult& aErr); void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
void SetStartBefore(nsINode& aNode, ErrorResult& aErr); void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
@ -469,16 +493,6 @@ protected:
const RawRangeBoundary& upperBound, const RawRangeBoundary& upperBound,
nsINode* aRoot, bool aNotInsertedYet = false); nsINode* aRoot, bool aNotInsertedYet = false);
void DoSetRange(nsINode* aStartContainer, uint32_t aStartOffset,
nsINode* aEndContainer, uint32_t aEndOffset,
nsINode* aRoot, bool aNotInsertedYet = false)
{
RawRangeBoundary start(aStartContainer, aStartOffset);
RawRangeBoundary end(aEndContainer, aEndOffset);
DoSetRange(start, end, aRoot, aNotInsertedYet);
}
/** /**
* For a range for which IsInSelection() is true, return the common ancestor * For a range for which IsInSelection() is true, return the common ancestor
* for the range, which we had to compute when the common ancestor changed or * for the range, which we had to compute when the common ancestor changed or

Просмотреть файл

@ -6116,8 +6116,10 @@ HTMLEditRules::GetNodesForOperation(
// The new end parent becomes the parent node of the text. // The new end parent becomes the parent node of the text.
// XXX We want nsRange::SetEnd(const RawRangeBoundary&) // XXX We want nsRange::SetEnd(const RawRangeBoundary&)
EditorRawDOMPoint atContainerOfSplitNode(atEnd.Container()); EditorRawDOMPoint atContainerOfSplitNode(atEnd.Container());
range->SetEnd(atContainerOfSplitNode.Container(), range->SetEnd(atContainerOfSplitNode, error);
atContainerOfSplitNode.Offset()); if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
}
} }
} }
} }
@ -6614,8 +6616,11 @@ HTMLEditRules::GetNodesFromPoint(
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
RefPtr<nsRange> range = new nsRange(aPoint.Container()); RefPtr<nsRange> range = new nsRange(aPoint.Container());
DebugOnly<nsresult> rv = range->SetStart(aPoint.Container(), aPoint.Offset()); IgnoredErrorResult error;
MOZ_ASSERT(NS_SUCCEEDED(rv)); range->SetStart(aPoint, error);
if (NS_WARN_IF(error.Failed())) {
MOZ_ASSERT(!error.Failed());
}
// Expand the range to include adjacent inlines // Expand the range to include adjacent inlines
PromoteRange(*range, aOperation); PromoteRange(*range, aOperation);
@ -8640,16 +8645,19 @@ HTMLEditRules::ConfirmSelectionInBody()
nsresult nsresult
HTMLEditRules::UpdateDocChangeRange(nsRange* aRange) HTMLEditRules::UpdateDocChangeRange(nsRange* aRange)
{ {
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_NOT_AVAILABLE;
}
// first make sure aRange is in the document. It might not be if // first make sure aRange is in the document. It might not be if
// portions of our editting action involved manipulating nodes // portions of our editting action involved manipulating nodes
// prior to placing them in the document (e.g., populating a list item // prior to placing them in the document (e.g., populating a list item
// before placing it in its list) // before placing it in its list)
nsCOMPtr<nsINode> startNode = aRange->GetStartContainer(); const RangeBoundary& atStart = aRange->StartRef();
if (NS_WARN_IF(!startNode)) { if (NS_WARN_IF(!atStart.IsSet())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
NS_ENSURE_STATE(mHTMLEditor); if (!mHTMLEditor->IsDescendantOfRoot(atStart.Container())) {
if (!mHTMLEditor->IsDescendantOfRoot(startNode)) {
// just return - we don't need to adjust mDocChangeRange in this case // just return - we don't need to adjust mDocChangeRange in this case
return NS_OK; return NS_OK;
} }
@ -8675,8 +8683,11 @@ HTMLEditRules::UpdateDocChangeRange(nsRange* aRange)
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Positive result means mDocChangeRange start is after aRange start. // Positive result means mDocChangeRange start is after aRange start.
if (result > 0) { if (result > 0) {
rv = mDocChangeRange->SetStart(startNode, aRange->StartOffset()); ErrorResult error;
NS_ENSURE_SUCCESS(rv, rv); mDocChangeRange->SetStart(atStart.AsRaw(), error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
} }
// compare ends of ranges // compare ends of ranges
@ -8685,12 +8696,15 @@ HTMLEditRules::UpdateDocChangeRange(nsRange* aRange)
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Negative result means mDocChangeRange end is before aRange end. // Negative result means mDocChangeRange end is before aRange end.
if (result < 0) { if (result < 0) {
nsINode* endNode = aRange->GetEndContainer(); const RangeBoundary& atEnd = aRange->EndRef();
if (NS_WARN_IF(!endNode)) { if (NS_WARN_IF(!atEnd.IsSet())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
rv = mDocChangeRange->SetEnd(endNode, aRange->EndOffset()); ErrorResult error;
NS_ENSURE_SUCCESS(rv, rv); mDocChangeRange->SetEnd(atEnd.AsRaw(), error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
} }
} }
return NS_OK; return NS_OK;