Bug 1753786 - Make `nsRange::ExcludeNonSelectableNodes` stop using `ErrorResult` r=mbrodesser

It never returns error since its return type is `void` and it does not take
out param whose type is `ErrorResult`.

Therefore, `ErrorResult` in it is used only for checking whether an error occurs
in the calling methods, but neither `SuppressException()` nor `StealNSResult()`
is called for avoiding assertions at destructing the instance.

For avoiding the assertion, and in this case, it should not use `ErrorResult`.
When the result is completely ignored, `IgnoreErrors()` should be used instead.
Otherwise, when it just needs to know whether an API call failed or not, it
should use `IgnoreErrors` to avoid the redundant calls of `ErrorResult` and
for the performance (`ErrorResult`'s destruction may appear in the profile if
it's used in a hot path).

Differential Revision: https://phabricator.services.mozilla.com/D138231
This commit is contained in:
Masayuki Nakano 2022-02-10 12:00:10 +00:00
Родитель 19da6bccd0
Коммит c9bf3f5dee
2 изменённых файлов: 65 добавлений и 46 удалений

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

@ -2985,7 +2985,6 @@ void nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges) {
// the outer loop.
nsIContent* firstNonSelectableContent = nullptr;
while (true) {
ErrorResult err;
nsINode* node = preOrderIter.GetCurrentNode();
preOrderIter.Next();
bool selectable = true;
@ -3013,63 +3012,71 @@ void nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges) {
if (!firstNonSelectableContent) {
firstNonSelectableContent = content;
}
if (preOrderIter.IsDone() && seenSelectable) {
// The tail end of the initial range is non-selectable - truncate the
// current range before the first non-selectable node.
range->SetEndBefore(*firstNonSelectableContent, err);
if (preOrderIter.IsDone()) {
if (seenSelectable) {
// The tail end of the initial range is non-selectable - truncate
// the current range before the first non-selectable node.
range->SetEndBefore(*firstNonSelectableContent, IgnoreErrors());
}
return;
}
} else if (firstNonSelectableContent) {
continue;
}
if (firstNonSelectableContent) {
if (range == this && !seenSelectable) {
// This is the initial range and all its nodes until now are
// non-selectable so just trim them from the start.
IgnoredErrorResult err;
range->SetStartBefore(*node, err);
if (err.Failed()) {
return;
}
break; // restart the same range with a new iterator
} else {
// Save the end point before truncating the range.
nsINode* endContainer = range->mEnd.Container();
const uint32_t endOffset =
*range->mEnd.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
// Truncate the current range before the first non-selectable node.
range->SetEndBefore(*firstNonSelectableContent, err);
// Store it in the result (strong ref) - do this before creating
// a new range in |newRange| below so we don't drop the last ref
// to the range created in the previous iteration.
if (!added && !err.Failed()) {
aOutRanges->AppendElement(range);
}
// Create a new range for the remainder.
nsINode* startContainer = node;
Maybe<uint32_t> startOffset = Some(0);
// Don't start *inside* a node with independent selection though
// (e.g. <input>).
if (content && content->HasIndependentSelection()) {
nsINode* parent = startContainer->GetParent();
if (parent) {
startOffset = parent->ComputeIndexOf(startContainer);
startContainer = parent;
}
}
newRange =
nsRange::Create(startContainer, startOffset.valueOr(UINT32_MAX),
endContainer, endOffset, IgnoreErrors());
if (!newRange || newRange->Collapsed()) {
newRange = nullptr;
}
range = newRange;
break; // create a new iterator for the new range, if any
}
} else {
seenSelectable = true;
if (!added) {
added = true;
// Save the end point before truncating the range.
nsINode* endContainer = range->mEnd.Container();
const uint32_t endOffset =
*range->mEnd.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
// Truncate the current range before the first non-selectable node.
IgnoredErrorResult err;
range->SetEndBefore(*firstNonSelectableContent, err);
// Store it in the result (strong ref) - do this before creating
// a new range in |newRange| below so we don't drop the last ref
// to the range created in the previous iteration.
if (!added && !err.Failed()) {
aOutRanges->AppendElement(range);
}
// Create a new range for the remainder.
nsINode* startContainer = node;
Maybe<uint32_t> startOffset = Some(0);
// Don't start *inside* a node with independent selection though
// (e.g. <input>).
if (content && content->HasIndependentSelection()) {
nsINode* parent = startContainer->GetParent();
if (parent) {
startOffset = parent->ComputeIndexOf(startContainer);
startContainer = parent;
}
}
newRange =
nsRange::Create(startContainer, startOffset.valueOr(UINT32_MAX),
endContainer, endOffset, IgnoreErrors());
if (!newRange || newRange->Collapsed()) {
newRange = nullptr;
}
range = newRange;
break; // create a new iterator for the new range, if any
}
seenSelectable = true;
if (!added) {
added = true;
aOutRanges->AppendElement(range);
}
if (preOrderIter.IsDone()) {
return;

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

@ -0,0 +1,12 @@
<!DOCTYPE html>
<meta charset="utf-8">
<script>
onload = () => {
document.querySelector("canvas[contenteditable]").blur();
document.execCommand("selectAll", false);
getSelection().modify("move", "forward", "lineboundary");
document.execCommand("selectAll", false);
};
</script>
<canvas contenteditable="true">
<audio controls>