Bug 1675883 - Use SetStartAndEndInLimiter() in SetSelectionInternal() r=masayuki

Differential Revision: https://phabricator.services.mozilla.com/D96503
This commit is contained in:
Kagami Sascha Rosylight 2020-11-12 14:28:39 +00:00
Родитель cd031ba211
Коммит 21c2a81d5e
2 изменённых файлов: 153 добавлений и 29 удалений

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

@ -793,25 +793,6 @@ already_AddRefed<TextEditor> nsTextControlFrame::GetTextEditor() {
nsresult nsTextControlFrame::SetSelectionInternal(
nsINode* aStartNode, uint32_t aStartOffset, nsINode* aEndNode,
uint32_t aEndOffset, nsITextControlFrame::SelectionDirection aDirection) {
// Create a new range to represent the new selection.
// Note that we use a new range to avoid having to do
// isIncreasing checks to avoid possible errors.
// Be careful to use internal nsRange methods which do not check to make sure
// we have access to the node.
// 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.
ErrorResult error;
RefPtr<nsRange> range =
nsRange::Create(aStartNode, aStartOffset, aEndNode, aEndOffset, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
MOZ_ASSERT(range);
// Get the selection, clear it and add the new range to it!
TextControlElement* textControlElement =
TextControlElement::FromNode(GetContent());
@ -831,16 +812,10 @@ nsresult nsTextControlFrame::SetSelectionInternal(
direction = (aDirection == eBackward) ? eDirPrevious : eDirNext;
}
selection->RemoveAllRanges(error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
selection->AddRangeAndSelectFramesAndNotifyListeners(
*range, error); // NOTE: can destroy the world
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
ErrorResult error;
selection->SetStartAndEndInLimiter(*aStartNode, aStartOffset, *aEndNode,
aEndOffset, error);
MOZ_TRY(error.StealNSResult());
selection->SetDirection(direction);
return NS_OK;

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

@ -0,0 +1,149 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Test selectionchange events from text controls</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="stylesheet" href="/fonts/ahem.css">
<style>
input,
textarea {
font: 16px/1 Ahem;
}
</style>
<input id="input" value="XXXXXXXXXXXXXXXXXXX" width="200"><br>
<textarea id="textarea" width="200">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</textarea>
<script>
class SelectionChangeCollector {
constructor(target) {
this.events = [];
target.addEventListener("selectionchange", ev => {
this.events.push(ev);
});
}
clear() {
this.events.length = 0;
}
}
const data = {
input: new SelectionChangeCollector(input),
textarea: new SelectionChangeCollector(textarea),
async initialize() {
input.blur();
textarea.blur();
input.selectionStart = input.selectionEnd = 0;
textarea.selectionStart = textarea.selectionEnd = 0;
await this.spin();
this.input.clear();
this.textarea.clear();
},
spin() {
return new Promise(setTimeout);
},
};
promise_test(async () => {
await data.initialize();
textarea.selectionStart = 1;
await data.spin();
assert_equals(data.textarea.events.length, 1);
}, "Modifying selectionStart value of the textarea element");
promise_test(async () => {
await data.initialize();
textarea.selectionEnd = 1;
await data.spin();
assert_equals(data.textarea.events.length, 1);
}, "Modifying selectionEnd value of the textarea element");
promise_test(async () => {
await data.initialize();
textarea.setSelectionRange(0, 4);
await data.spin();
assert_equals(data.textarea.events.length, 1);
}, "Calling setSelectionRange on the textarea element");
promise_test(async () => {
await data.initialize();
input.selectionStart = 0;
await data.spin();
assert_equals(data.input.events.length, 0);
}, "Setting initial zero selectionStart value on the input element");
promise_test(async () => {
await data.initialize();
input.selectionEnd = 0;
await data.spin();
assert_equals(data.input.events.length, 0);
}, "Setting initial zero selectionEnd value on the input element");
promise_test(async () => {
await data.initialize();
textarea.selectionStart = 0;
await data.spin();
assert_equals(data.textarea.events.length, 0);
}, "Setting initial zero selectionStart value on the textarea element");
promise_test(async () => {
await data.initialize();
textarea.selectionStart = 2;
textarea.selectionStart = 2;
await data.spin();
assert_equals(data.textarea.events.length, 1);
}, "Setting the same selectionStart value on the textarea element twice");
promise_test(async () => {
await data.initialize();
textarea.selectionEnd = 0;
await data.spin();
assert_equals(data.textarea.events.length, 0);
}, "Setting initial zero selectionEnd value on the textarea element");
promise_test(async () => {
await data.initialize();
textarea.selectionEnd = 2;
textarea.selectionEnd = 2;
await data.spin();
assert_equals(data.textarea.events.length, 1);
}, "Setting the same selectionEnd value on the textarea element twice");
promise_test(async () => {
await data.initialize();
textarea.setSelectionRange(0, 0);
await data.spin();
assert_equals(data.textarea.events.length, 0);
}, "Setting initial zero selection range on the textarea element");
promise_test(async () => {
await data.initialize();
textarea.setSelectionRange(3, 3);
textarea.setSelectionRange(3, 3);
await data.spin();
assert_equals(data.textarea.events.length, 1);
}, "Setting the same selection range on the textarea element twice");
</script>