Bug 1367683 Optimize initializing nsRange r=smaug

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
This commit is contained in:
Masayuki Nakano 2017-05-30 13:18:25 +09:00
Родитель 242d05ee83
Коммит 61af94acbd
16 изменённых файлов: 332 добавлений и 213 удалений

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

@ -6734,7 +6734,7 @@ already_AddRefed<nsRange>
nsIDocument::CreateRange(ErrorResult& rv)
{
RefPtr<nsRange> range = new nsRange(this);
nsresult res = range->Set(this, 0, this, 0);
nsresult res = range->CollapseTo(this, 0);
if (NS_FAILED(res)) {
rv.Throw(res);
return nullptr;

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

@ -271,14 +271,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 */
@ -287,24 +290,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);
// XXX this can be optimized by inlining SetStart/End and calling
// DoSetRange *once*.
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 */
@ -1149,6 +1137,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)
{
@ -1237,7 +1234,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;
}
@ -1274,7 +1271,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
@ -1308,7 +1307,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
@ -1365,7 +1366,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;
}
@ -1384,6 +1385,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::SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr)
{
@ -1402,7 +1461,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
@ -1436,7 +1497,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

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

@ -149,19 +149,61 @@ public:
nsINode* GetCommonAncestor() const;
void Reset();
/**
* SetStart() and SetEnd() sets start point or end point separately.
* However, this is expensive especially when it's a range of Selection.
* When you set both start and end of a range, you should use
* SetStartAndEnd() instead.
*/
nsresult SetStart(nsINode* aParent, int32_t aOffset);
nsresult SetEnd(nsINode* aParent, int32_t aOffset);
already_AddRefed<nsRange> CloneRange() const;
nsresult Set(nsINode* aStartParent, int32_t aStartOffset,
nsINode* aEndParent, int32_t aEndOffset)
{
// If this starts being hot, we may be able to optimize this a bit,
// but for now just set start and end separately.
nsresult rv = SetStart(aStartParent, aStartOffset);
NS_ENSURE_SUCCESS(rv, rv);
/**
* SetStartAndEnd() works similar to call both SetStart() and SetEnd().
* Different from calls them separately, this does nothing if either
* the start point or the end point is invalid point.
* If the specified start point is after the end point, the range will be
* collapsed at the end point. Similarly, if they are in different root,
* the range will be collapsed at the end point.
*/
nsresult SetStartAndEnd(nsINode* aStartParent, int32_t aStartOffset,
nsINode* aEndParent, int32_t aEndOffset);
return SetEnd(aEndParent, aEndOffset);
/**
* CollapseTo() works similar to call both SetStart() and SetEnd() with
* same node and offset. This just calls SetStartAndParent() to set
* collapsed range at aParent and aOffset.
*/
nsresult CollapseTo(nsINode* aParent, int32_t aOffset)
{
return SetStartAndEnd(aParent, aOffset, aParent, aOffset);
}
/**
* Retrieves node and offset for setting start or end of a range to
* before or after aNode.
*/
static nsINode* GetParentAndOffsetAfter(nsINode* aNode, int32_t* aOffset)
{
MOZ_ASSERT(aNode);
MOZ_ASSERT(aOffset);
nsINode* parentNode = aNode->GetParentNode();
*aOffset = parentNode ? parentNode->IndexOf(aNode) : -1;
if (*aOffset >= 0) {
(*aOffset)++;
}
return parentNode;
}
static nsINode* GetParentAndOffsetBefore(nsINode* aNode, int32_t* aOffset)
{
MOZ_ASSERT(aNode);
MOZ_ASSERT(aOffset);
nsINode* parentNode = aNode->GetParentNode();
*aOffset = parentNode ? parentNode->IndexOf(aNode) : -1;
return parentNode;
}
NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
@ -314,6 +356,7 @@ protected:
void RegisterCommonAncestor(nsINode* aNode);
void UnregisterCommonAncestor(nsINode* aNode);
nsINode* IsValidBoundary(nsINode* aNode);
static bool IsValidOffset(nsINode* aNode, int32_t aOffset);
// CharacterDataChanged set aNotInsertedYet to true to disable an assertion
// and suppress re-registering a range common ancestor node since

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

@ -985,11 +985,7 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
// Special case like <br contenteditable>
if (!mRootContent->HasChildren()) {
nsresult rv = aRange->SetStart(mRootContent, 0);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = aRange->SetEnd(mRootContent, 0);
nsresult rv = aRange->CollapseTo(mRootContent, 0);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2883,8 +2879,7 @@ ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(nsRange* aRange)
return NS_OK;
}
nsresult rv = aRange->Set(childNode, offsetInChildNode,
childNode, offsetInChildNode);
nsresult rv = aRange->CollapseTo(childNode, offsetInChildNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

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

@ -1445,16 +1445,15 @@ HTMLEditRules::WillInsertText(EditAction aAction,
if (!mDocChangeRange) {
mDocChangeRange = new nsRange(selNode);
}
rv = mDocChangeRange->SetStart(selNode, selOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (curNode) {
rv = mDocChangeRange->SetEnd(curNode, curOffset);
rv = mDocChangeRange->SetStartAndEnd(selNode, selOffset,
curNode, curOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
rv = mDocChangeRange->SetEnd(selNode, selOffset);
rv = mDocChangeRange->CollapseTo(selNode, selOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -5250,10 +5249,11 @@ HTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
// Create a range that represents expanded selection
RefPtr<nsRange> range = new nsRange(selStartNode);
nsresult rv = range->SetStart(selStartNode, selStartOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SetEnd(selEndNode, selEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = range->SetStartAndEnd(selStartNode, selStartOffset,
selEndNode, selEndOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Check if block is entirely inside range
if (brBlock) {
@ -5714,26 +5714,27 @@ HTMLEditRules::PromoteRange(nsRange& aRange,
// This is tricky. The basic idea is to push out the range endpoints to
// truly enclose the blocks that we will affect.
nsCOMPtr<nsIDOMNode> opStartNode;
nsCOMPtr<nsIDOMNode> opEndNode;
nsCOMPtr<nsIDOMNode> opDOMStartNode;
nsCOMPtr<nsIDOMNode> opDOMEndNode;
int32_t opStartOffset, opEndOffset;
GetPromotedPoint(kStart, GetAsDOMNode(startNode), startOffset,
aOperationType, address_of(opStartNode), &opStartOffset);
aOperationType, address_of(opDOMStartNode), &opStartOffset);
GetPromotedPoint(kEnd, GetAsDOMNode(endNode), endOffset, aOperationType,
address_of(opEndNode), &opEndOffset);
address_of(opDOMEndNode), &opEndOffset);
// Make sure that the new range ends up to be in the editable section.
if (!htmlEditor->IsDescendantOfEditorRoot(
EditorBase::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) ||
EditorBase::GetNodeAtRangeOffsetPoint(opDOMStartNode, opStartOffset)) ||
!htmlEditor->IsDescendantOfEditorRoot(
EditorBase::GetNodeAtRangeOffsetPoint(opEndNode, opEndOffset - 1))) {
EditorBase::GetNodeAtRangeOffsetPoint(opDOMEndNode, opEndOffset - 1))) {
return;
}
DebugOnly<nsresult> rv = aRange.SetStart(opStartNode, opStartOffset);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = aRange.SetEnd(opEndNode, opEndOffset);
nsCOMPtr<nsINode> opStartNode = do_QueryInterface(opDOMStartNode);
nsCOMPtr<nsINode> opEndNode = do_QueryInterface(opDOMEndNode);
DebugOnly<nsresult> rv =
aRange.SetStartAndEnd(opStartNode, opStartOffset, opEndNode, opEndOffset);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
@ -7400,10 +7401,10 @@ HTMLEditRules::PinSelectionToNewBlock(Selection* aSelection)
nsCOMPtr<nsINode> node = do_QueryInterface(selNode);
NS_ENSURE_STATE(node);
RefPtr<nsRange> range = new nsRange(node);
rv = range->SetStart(selNode, selOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SetEnd(selNode, selOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = range->CollapseTo(node, selOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
bool nodeBefore, nodeAfter;
rv = nsRange::CompareNodeToRange(mNewBlock, range, &nodeBefore, &nodeAfter);
NS_ENSURE_SUCCESS(rv, rv);
@ -8298,10 +8299,13 @@ HTMLEditRules::DidSplitNode(nsIDOMNode* aExistingRightNode,
if (!mListenerEnabled) {
return NS_OK;
}
nsresult rv = mUtilRange->SetStart(aNewLeftNode, 0);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUtilRange->SetEnd(aExistingRightNode, 0);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> newLeftNode = do_QueryInterface(aNewLeftNode);
nsCOMPtr<nsINode> existingRightNode = do_QueryInterface(aExistingRightNode);
nsresult rv = mUtilRange->SetStartAndEnd(newLeftNode, 0,
existingRightNode, 0);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return UpdateDocChangeRange(mUtilRange);
}
@ -8326,11 +8330,12 @@ HTMLEditRules::DidJoinNodes(nsIDOMNode* aLeftNode,
if (!mListenerEnabled) {
return NS_OK;
}
nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode);
// assumption that Join keeps the righthand node
nsresult rv = mUtilRange->SetStart(aRightNode, mJoinOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUtilRange->SetEnd(aRightNode, mJoinOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = mUtilRange->CollapseTo(rightNode, mJoinOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return UpdateDocChangeRange(mUtilRange);
}
@ -8352,11 +8357,12 @@ HTMLEditRules::DidInsertText(nsIDOMCharacterData* aTextNode,
return NS_OK;
}
int32_t length = aString.Length();
nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
nsresult rv = mUtilRange->SetStart(theNode, aOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUtilRange->SetEnd(theNode, aOffset+length);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode);
nsresult rv = mUtilRange->SetStartAndEnd(theNode, aOffset,
theNode, aOffset + length);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return UpdateDocChangeRange(mUtilRange);
}
@ -8377,11 +8383,11 @@ HTMLEditRules::DidDeleteText(nsIDOMCharacterData* aTextNode,
if (!mListenerEnabled) {
return NS_OK;
}
nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
nsresult rv = mUtilRange->SetStart(theNode, aOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUtilRange->SetEnd(theNode, aOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode);
nsresult rv = mUtilRange->CollapseTo(theNode, aOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return UpdateDocChangeRange(mUtilRange);
}
@ -8396,20 +8402,25 @@ HTMLEditRules::WillDeleteSelection(nsISelection* aSelection)
}
RefPtr<Selection> selection = aSelection->AsSelection();
// get the (collapsed) selection location
nsCOMPtr<nsIDOMNode> selNode;
int32_t selOffset;
nsCOMPtr<nsINode> startNode;
int32_t startOffset;
nsresult rv =
EditorBase::GetStartNodeAndOffset(selection,
getter_AddRefs(selNode), &selOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUtilRange->SetStart(selNode, selOffset);
NS_ENSURE_SUCCESS(rv, rv);
getter_AddRefs(startNode), &startOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsINode> endNode;
int32_t endOffset;
rv = EditorBase::GetEndNodeAndOffset(selection,
getter_AddRefs(selNode), &selOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUtilRange->SetEnd(selNode, selOffset);
NS_ENSURE_SUCCESS(rv, rv);
getter_AddRefs(endNode), &endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = mUtilRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return UpdateDocChangeRange(mUtilRange);
}

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

@ -3287,8 +3287,8 @@ HTMLEditor::DoContentInserted(nsIDocument* aDocument,
sibling = sibling->GetNextSibling();
}
}
nsresult rv = range->Set(aContainer, aIndexInContainer,
aContainer, endIndex);
nsresult rv = range->SetStartAndEnd(aContainer, aIndexInContainer,
aContainer, endIndex);
if (NS_SUCCEEDED(rv)) {
mInlineSpellChecker->SpellCheckRange(range);
}

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

@ -536,9 +536,11 @@ HTMLEditor::SplitStyleAboveRange(nsRange* inRange,
NS_ENSURE_SUCCESS(rv, rv);
// reset the range
rv = inRange->SetStart(startNode, startOffset);
NS_ENSURE_SUCCESS(rv, rv);
return inRange->SetEnd(endNode, endOffset);
rv = inRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
@ -883,10 +885,11 @@ HTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange)
endOffset = endNode ? endNode->IndexOf(parent) + 1 : 0;
}
nsresult rv = aRange.SetStart(startNode, startOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = aRange.SetEnd(endNode, endOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = aRange.SetStartAndEnd(startNode, startOffset,
endNode, endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
@ -916,10 +919,11 @@ HTMLEditor::PromoteInlineRange(nsRange& aRange)
endNode = parent;
}
nsresult rv = aRange.SetStart(startNode, startOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = aRange.SetEnd(endNode, endOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = aRange.SetStartAndEnd(startNode, startOffset,
endNode, endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}

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

@ -686,7 +686,8 @@ already_AddRefed<nsRange>
RangeItem::GetRange()
{
RefPtr<nsRange> range = new nsRange(startNode);
if (NS_FAILED(range->Set(startNode, startOffset, endNode, endOffset))) {
if (NS_FAILED(range->SetStartAndEnd(startNode, startOffset,
endNode, endOffset))) {
return nullptr;
}
return range.forget();

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

@ -1296,7 +1296,7 @@ WSRunObject::DeleteChars(nsINode* aStartNode,
if (!range) {
range = new nsRange(aStartNode);
nsresult rv =
range->Set(aStartNode, aStartOffset, aEndNode, aEndOffset);
range->SetStartAndEnd(aStartNode, aStartOffset, aEndNode, aEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
}
bool nodeBefore, nodeAfter;

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

@ -406,11 +406,13 @@ nsTextServicesDocument::ExpandRangeToWordBoundaries(nsIDOMRange *aRange)
// Now adjust the range so that it uses our new
// end points.
rv = range->SetEnd(rngEndNode, rngEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
return range->SetStart(rngStartNode, rngStartOffset);
nsCOMPtr<nsINode> startNode = do_QueryInterface(rngStartNode);
nsCOMPtr<nsINode> endNode = do_QueryInterface(rngEndNode);
rv = range->SetStartAndEnd(startNode, rngStartOffset, endNode, rngEndOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
NS_IMETHODIMP

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

@ -164,16 +164,23 @@ mozInlineSpellStatus::InitForEditorChange(
NS_ENSURE_SUCCESS(rv, rv);
if (cmpResult < 0) {
// previous anchor node is before the current anchor
rv = mRange->SetStart(aPreviousNode, aPreviousOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mRange->SetEnd(aAnchorNode, aAnchorOffset);
nsCOMPtr<nsINode> previousNode = do_QueryInterface(aPreviousNode);
nsCOMPtr<nsINode> anchorNode = do_QueryInterface(aAnchorNode);
rv = mRange->SetStartAndEnd(previousNode, aPreviousOffset,
anchorNode, aAnchorOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
// previous anchor node is after (or the same as) the current anchor
rv = mRange->SetStart(aAnchorNode, aAnchorOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mRange->SetEnd(aPreviousNode, aPreviousOffset);
nsCOMPtr<nsINode> previousNode = do_QueryInterface(aPreviousNode);
nsCOMPtr<nsINode> anchorNode = do_QueryInterface(aAnchorNode);
rv = mRange->SetStartAndEnd(anchorNode, aAnchorOffset,
previousNode, aPreviousOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
NS_ENSURE_SUCCESS(rv, rv);
// On insert save this range: DoSpellCheck optimizes things in this range.
// Otherwise, just leave this nullptr.
@ -454,17 +461,19 @@ mozInlineSpellStatus::GetDocument(nsIDOMDocument** aDocument)
nsresult
mozInlineSpellStatus::PositionToCollapsedRange(nsIDOMDocument* aDocument,
nsIDOMNode* aNode, int32_t aOffset, nsIDOMRange** aRange)
nsIDOMNode* aNode,
int32_t aOffset,
nsRange** aRange)
{
*aRange = nullptr;
nsCOMPtr<nsIDOMRange> range;
nsresult rv = aDocument->CreateRange(getter_AddRefs(range));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> documentNode = do_QueryInterface(aDocument);
RefPtr<nsRange> range = new nsRange(documentNode);
rv = range->SetStart(aNode, aOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SetEnd(aNode, aOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
nsresult rv = range->CollapseTo(node, aOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
range.swap(*aRange);
return NS_OK;
@ -1167,9 +1176,8 @@ mozInlineSpellChecker::MakeSpellCheckRange(
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMRange> range;
rv = doc->CreateRange(getter_AddRefs(range));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> documentNode = do_QueryInterface(doc);
RefPtr<nsRange> range = new nsRange(documentNode);
// possibly use full range of the editor
nsCOMPtr<nsIDOMElement> rootElem;
@ -1201,15 +1209,23 @@ mozInlineSpellChecker::MakeSpellCheckRange(
if (aStartNode == aEndNode && aStartOffset == aEndOffset)
return NS_OK;
rv = range->SetStart(aStartNode, aStartOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (aEndOffset)
rv = range->SetEnd(aEndNode, aEndOffset);
else
rv = range->SetEndAfter(aEndNode);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> startNode = do_QueryInterface(aStartNode);
nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
if (aEndOffset) {
rv = range->SetStartAndEnd(startNode, aStartOffset, endNode, aEndOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
int32_t endOffset = -1;
endNode = nsRange::GetParentAndOffsetAfter(endNode, &endOffset);
rv = range->SetStartAndEnd(startNode, aStartOffset, endNode, endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
*aRange = static_cast<nsRange*>(range.forget().take());
range.swap(*aRange);
return NS_OK;
}

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

@ -85,7 +85,7 @@ public:
// (such as for the intial check of everything).
//
// For mOp == eOpNavigation, this is the NEW position of the cursor
nsCOMPtr<nsIDOMRange> mAnchorRange;
RefPtr<nsRange> mAnchorRange;
// -----
// The following members are only for navigation events and are only
@ -93,7 +93,7 @@ public:
// -----
// this is the OLD position of the cursor
nsCOMPtr<nsIDOMRange> mOldNavigationAnchorRange;
RefPtr<nsRange> mOldNavigationAnchorRange;
// Set when we should force checking the current word. See
// mozInlineSpellChecker::HandleNavigationEvent for a description of why we
@ -111,7 +111,7 @@ protected:
nsresult GetDocument(nsIDOMDocument** aDocument);
nsresult PositionToCollapsedRange(nsIDOMDocument* aDocument,
nsIDOMNode* aNode, int32_t aOffset,
nsIDOMRange** aRange);
nsRange** aRange);
};
class mozInlineSpellChecker final : public nsIInlineSpellChecker,

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

@ -335,9 +335,11 @@ mozInlineSpellWordUtil::MakeRange(NodeOffset aBegin, NodeOffset aEnd,
return NS_ERROR_NOT_INITIALIZED;
RefPtr<nsRange> range = new nsRange(aBegin.mNode);
nsresult rv = range->Set(aBegin.mNode, aBegin.mOffset,
aEnd.mNode, aEnd.mOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = range->SetStartAndEnd(aBegin.mNode, aBegin.mOffset,
aEnd.mNode, aEnd.mOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
range.forget(aRange);
return NS_OK;

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

@ -755,12 +755,12 @@ nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode,
// we have access to the node.
nsCOMPtr<nsINode> start = do_QueryInterface(aStartNode);
nsCOMPtr<nsINode> end = do_QueryInterface(aEndNode);
// XXXbz nsRange::Set takes int32_t (and ranges generally work on int32_t),
// but we're passing uint32_t. The good news is that at this point our
// endpoints should really be within our length, so not really that big. And
// if they _are_ that big, Set() will simply error out, which is not too bad
// for a case we don't expect to happen.
nsresult rv = range->Set(start, aStartOffset, end, aEndOffset);
// XXXbz nsRange::SetStartAndEnd takes int32_t (and ranges generally work on
// int32_t), but we're passing uint32_t. The good news is that at this point
// our endpoints should really be within our length, so not really that big.
// And if they _are_ that big, SetStartAndEnd() will simply error out, which
// is not too bad for a case we don't expect to happen.
nsresult rv = range->SetStartAndEnd(start, aStartOffset, end, aEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Get the selection, clear it and add the new range to it!

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

@ -1795,8 +1795,7 @@ nsFrameSelection::TakeFocus(nsIContent* aNewFocus,
RefPtr<nsRange> newRange = new nsRange(aNewFocus);
newRange->SetStart(aNewFocus, aContentOffset);
newRange->SetEnd(aNewFocus, aContentOffset);
newRange->CollapseTo(aNewFocus, aContentOffset);
mDomSelections[index]->AddRange(newRange);
mBatching = batching;
mChangesDuringBatching = changes;
@ -3368,11 +3367,12 @@ nsFrameSelection::CreateAndAddRange(nsINode *aParentNode, int32_t aOffset)
RefPtr<nsRange> range = new nsRange(aParentNode);
// Set range around child at given offset
nsresult result = range->SetStart(aParentNode, aOffset);
if (NS_FAILED(result)) return result;
result = range->SetEnd(aParentNode, aOffset+1);
if (NS_FAILED(result)) return result;
nsresult rv = range->SetStartAndEnd(aParentNode, aOffset,
aParentNode, aOffset + 1);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
if (!mDomSelections[index])
return NS_ERROR_NULL_POINTER;
@ -3800,13 +3800,12 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
// We need to add a new RangeData to the output, running from
// the end of aSubtract to the end of range
RefPtr<nsRange> postOverlap = new nsRange(aSubtract->GetEndParent());
rv =
postOverlap->SetStart(aSubtract->GetEndParent(), aSubtract->EndOffset());
NS_ENSURE_SUCCESS(rv, rv);
rv =
postOverlap->SetEnd(range->GetEndParent(), range->EndOffset());
NS_ENSURE_SUCCESS(rv, rv);
rv = postOverlap->SetStartAndEnd(
aSubtract->GetEndParent(), aSubtract->EndOffset(),
range->GetEndParent(), range->EndOffset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!postOverlap->Collapsed()) {
if (!aOutput->InsertElementAt(0, RangeData(postOverlap)))
return NS_ERROR_OUT_OF_MEMORY;
@ -3818,14 +3817,12 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
// We need to add a new RangeData to the output, running from
// the start of the range to the start of aSubtract
RefPtr<nsRange> preOverlap = new nsRange(range->GetStartParent());
nsresult rv =
preOverlap->SetStart(range->GetStartParent(), range->StartOffset());
NS_ENSURE_SUCCESS(rv, rv);
rv =
preOverlap->SetEnd(aSubtract->GetStartParent(), aSubtract->StartOffset());
NS_ENSURE_SUCCESS(rv, rv);
rv = preOverlap->SetStartAndEnd(
range->GetStartParent(), range->StartOffset(),
aSubtract->GetStartParent(), aSubtract->StartOffset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!preOverlap->Collapsed()) {
if (!aOutput->InsertElementAt(0, RangeData(preOverlap)))
return NS_ERROR_OUT_OF_MEMORY;
@ -5277,12 +5274,7 @@ Selection::Collapse(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
RefPtr<nsRange> range = new nsRange(parentNode);
result = range->SetEnd(parentNode, aOffset);
if (NS_FAILED(result)) {
aRv.Throw(result);
return;
}
result = range->SetStart(parentNode, aOffset);
result = range->CollapseTo(parentNode, aOffset);
if (NS_FAILED(result)) {
aRv.Throw(result);
return;
@ -5685,11 +5677,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
return;
}
SetDirection(eDirNext);
res = difRange->SetEnd(range->GetEndParent(), range->EndOffset());
nsresult tmp = difRange->SetStart(focusNode, focusOffset);
if (NS_FAILED(tmp)) {
res = tmp;
}
res = difRange->SetStartAndEnd(focusNode, focusOffset,
range->GetEndParent(), range->EndOffset());
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@ -5717,11 +5706,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
else if (result3 <= 0 && result2 >= 0) {//a,2,1 or a2,1 or a,21 or a21
//deselect from 2 to 1
res = difRange->SetEnd(focusNode, focusOffset);
difRange->SetStart(aParentNode, aOffset, aRv);
if (aRv.Failed()) {
return;
}
res = difRange->SetStartAndEnd(&aParentNode, aOffset,
focusNode, focusOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@ -5785,11 +5771,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
else if (result2 <= 0 && result3 >= 0) {//1,2,a or 12,a or 1,2a or 12a
//deselect from 1 to 2
difRange->SetEnd(aParentNode, aOffset, aRv);
res = difRange->SetStart(focusNode, focusOffset);
if (aRv.Failed()) {
return;
}
res = difRange->SetStartAndEnd(focusNode, focusOffset,
&aParentNode, aOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@ -5820,12 +5803,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
//deselect from a to 1
if (focusNode != anchorNode || focusOffset!= anchorOffset) {//if collapsed diff dont do anything
res = difRange->SetStart(anchorNode, anchorOffset);
nsresult tmp = difRange->SetEnd(focusNode, focusOffset);
if (NS_FAILED(tmp)) {
res = tmp;
}
tmp = SetAnchorFocusToRange(range);
res = difRange->SetStartAndEnd(anchorNode, anchorOffset,
focusNode, focusOffset);
nsresult tmp = SetAnchorFocusToRange(range);
if (NS_FAILED(tmp)) {
res = tmp;
}
@ -5853,11 +5833,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
return;
}
SetDirection(eDirPrevious);
res = difRange->SetEnd(focusNode, focusOffset);
nsresult tmp = difRange->SetStart(range->GetStartParent(), range->StartOffset());
if (NS_FAILED(tmp)) {
res = tmp;
}
res = difRange->SetStartAndEnd(
range->GetStartParent(), range->StartOffset(),
focusNode, focusOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;

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

@ -2451,13 +2451,17 @@ CloneRangeToSelection(nsRange* aRange, nsIDocument* aDoc,
NS_ENSURE_TRUE_VOID(newStart && newEnd);
nsCOMPtr<nsINode> newStartNode = do_QueryInterface(newStart);
NS_ENSURE_TRUE_VOID(newStartNode);
nsCOMPtr<nsINode> newEndNode = do_QueryInterface(newEnd);
if (NS_WARN_IF(!newStartNode) || NS_WARN_IF(!newEndNode)) {
return;
}
RefPtr<nsRange> range = new nsRange(newStartNode);
nsresult rv = range->SetStart(newStartNode, startOffset);
NS_ENSURE_SUCCESS_VOID(rv);
rv = range->SetEnd(newEnd, endOffset);
NS_ENSURE_SUCCESS_VOID(rv);
nsresult rv =
range->SetStartAndEnd(newStartNode, startOffset, newEndNode, endOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
aSelection->AddRange(range);
}