LibWeb: Use UTF-16 code units length in CharacterData::replace_data()
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run

Range API uses UTF-16 code units to represent offsets, so replace_data()
needs to use it instead of bytes count while calculating new offsets.

Fixes incorrectly thrown exception when non-latin string is passed into
replace_data().
This commit is contained in:
Aliaksandr Kalenik 2024-11-06 04:26:56 +01:00 committed by Tim Ledbetter
parent f7dfe03cf6
commit 42b31820a6
Notes: github-actions[bot] 2024-11-06 05:47:30 +00:00
3 changed files with 18 additions and 2 deletions

View file

@ -0,0 +1 @@
=Привет=

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<script src="include.js"></script>
<div id="text">==</div>
<script>
test(() => {
const text = document.getElementById("text");
const range = document.createRange();
range.setStart(text.firstChild, 0);
range.setEnd(text.firstChild, text.firstChild.length);
text.firstChild.insertData(1, "Привет");
println(range.toString());
});
</script>

View file

@ -72,6 +72,8 @@ WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t coun
Utf16View utf16_view { utf16_data }; Utf16View utf16_view { utf16_data };
auto length = utf16_view.length_in_code_units(); auto length = utf16_view.length_in_code_units();
auto inserted_data_length_in_utf16_code_units = AK::utf16_code_unit_length_from_utf8(data);
// 2. If offset is greater than length, then throw an "IndexSizeError" DOMException. // 2. If offset is greater than length, then throw an "IndexSizeError" DOMException.
if (offset > length) if (offset > length)
return WebIDL::IndexSizeError::create(realm(), "Replacement offset out of range."_string); return WebIDL::IndexSizeError::create(realm(), "Replacement offset out of range."_string);
@ -107,14 +109,14 @@ WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t coun
// 10. For each live range whose start node is node and start offset is greater than offset plus count, increase its start offset by datas length and decrease it by count. // 10. For each live range whose start node is node and start offset is greater than offset plus count, increase its start offset by datas length and decrease it by count.
for (auto& range : Range::live_ranges()) { for (auto& range : Range::live_ranges()) {
if (range->start_container() == this && range->start_offset() > (offset + count)) if (range->start_container() == this && range->start_offset() > (offset + count))
TRY(range->set_start(*range->start_container(), range->start_offset() + data.bytes().size() - count)); TRY(range->set_start(*range->start_container(), range->start_offset() + inserted_data_length_in_utf16_code_units - count));
} }
// 11. For each live range whose end node is node and end offset is greater than offset plus count, increase its end offset by datas length and decrease it by count. // 11. For each live range whose end node is node and end offset is greater than offset plus count, increase its end offset by datas length and decrease it by count.
for (auto& range : Range::live_ranges()) { for (auto& range : Range::live_ranges()) {
if (range->end_container() == this && range->end_offset() > (offset + count)) { if (range->end_container() == this && range->end_offset() > (offset + count)) {
// AD-HOC: Clamp offset to the end of the data if it's too large. // AD-HOC: Clamp offset to the end of the data if it's too large.
auto new_offset = min(range->end_offset() + data.bytes().size() - count, m_data.bytes().size()); auto new_offset = min(range->end_offset() + inserted_data_length_in_utf16_code_units - count, length_in_utf16_code_units());
TRY(range->set_end(*range->end_container(), new_offset)); TRY(range->set_end(*range->end_container(), new_offset));
} }
} }