Bug 1745862 - part 1: Make `RangeBoundary::DetermineOffsetFromReference()` not set `mOffset` if `mRef` is being removed from the parent r=mbrodesser

It assumes that `mRef` is always in `mParent`, but this may be called when
`mRef` is **being** removed from `mParent`.  In the case, `mRef` still thinks
`mParent` is its parent, but it's already been removed from the child node chain
of `mParent`.  Therefore, `mParent->ComputeIndexOf(mRef)` may return `Nothing`.

This patch makes it keeps `mOffset` as `Nothing` in the case, and if the caller
wants invalid offset, this makes it use the fallback path.  I.e., this patch
changes the behavior of `RangeBoundary::Offset(kValidOffset)`.

Differential Revision: https://phabricator.services.mozilla.com/D134678
This commit is contained in:
Masayuki Nakano 2022-01-13 13:25:15 +00:00
Родитель edcdc5567a
Коммит 96af7451e9
2 изменённых файлов: 28 добавлений и 2 удалений

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

@ -183,7 +183,9 @@ class RangeBoundaryBase {
if (mParent) {
DetermineOffsetFromReference();
return mOffset;
if (mOffset.isSome()) {
return mOffset;
}
}
return Some(kFallbackOffset);
@ -202,10 +204,17 @@ class RangeBoundaryBase {
MOZ_ASSERT(mParent);
MOZ_ASSERT(mRef);
MOZ_ASSERT(mRef->GetParentNode() == mParent);
MOZ_ASSERT(mOffset.isNothing());
const Maybe<uint32_t> index = mParent->ComputeIndexOf(mRef);
// If mRef is **being** removed from mParent, ComputeIndexOf returns
// Nothing because mRef has already been removed from the child node chain
// of mParent.
if (index.isNothing()) {
return;
}
MOZ_ASSERT(*index != UINT32_MAX);
mOffset.emplace(MOZ_LIKELY(index.isSome()) ? *index + 1u : 0u);
mOffset.emplace(*index + 1u);
}
void InvalidateOffset() {

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<script>
window.onload = () => {
let s = window.getSelection()
let r = document.createRange()
r.selectNode(document.getElementById('b'))
s.addRange(r)
r = document.createRange()
r.selectNode(document.getElementById('a'))
s.addRange(r)
document.documentElement.innerHTML = ''
}
</script>
<body id='a' contenteditable='true'>
<canvas tabindex='0'>
<audio id='b'>