commit 1377eb0f8e3a822980ba4fb65d053ed4aa3670f5
parent 95420b7ba8e953959bb92163af00223cadb993fd
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Thu, 8 Jan 2026 09:02:08 +0000
Bug 2008590 - Deal with range insertions that contain the document element. r=TYLin,layout-reviewers
Before the regressing bug we relied on GetRangeInsertionPoint to do
this, but it's not really necessary. If the root element is on the range
deal with it, otherwise bail, which is what we were already doing.
Differential Revision: https://phabricator.services.mozilla.com/D278124
Diffstat:
2 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
@@ -6037,17 +6037,12 @@ nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
nsIContent* aEndChild,
InsertionKind aInsertionKind) {
MOZ_ASSERT(aStartChild);
-
- nsIContent* parent = aStartChild->GetParent();
- if (!parent) {
- IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
- return {};
- }
+ MOZ_ASSERT(aStartChild->GetParentNode());
// If the children of the container may be distributed to different insertion
// points, insert them separately and bail out, letting ContentInserted handle
// the mess.
- if (parent->GetShadowRoot()) {
+ if (aStartChild->GetParentNode()->GetShadowRoot()) {
IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
return {};
}
@@ -6228,17 +6223,23 @@ void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
}
#endif
- const bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
-
// If we have a null parent, then this must be the document element being
- // inserted, or some other child of the document in the DOM (might be a PI,
- // say).
+ // inserted, or some other child of the document in the DOM (might be a
+ // processing instruction or comment).
if (!aStartChild->GetParent()) {
- MOZ_ASSERT(isSingleInsert,
- "root node insertion should be a single insertion");
Element* docElement = mDocument->GetRootElement();
- if (aStartChild != docElement) {
- // Not the root element; just bail out
+ const bool foundRoot = [&] {
+ for (nsIContent* cur = aStartChild; cur != aEndChild;
+ cur = cur->GetNextSibling()) {
+ if (cur == docElement) {
+ return true;
+ }
+ }
+ return false;
+ }();
+
+ if (!foundRoot) {
+ // Not the root element (could be e.g. a comment), just bail out
return;
}
@@ -6251,7 +6252,7 @@ void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
// Create frames for the document element and its child elements
if (ConstructDocElementFrame(docElement)) {
- InvalidateCanvasIfNeeded(mPresShell, aStartChild);
+ InvalidateCanvasIfNeeded(mPresShell, docElement);
#ifdef DEBUG
if (gReallyNoisyContentUpdates) {
printf(
@@ -6267,10 +6268,10 @@ void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
}
#endif
-
return;
}
+ const bool isSingleInsert = aStartChild->GetNextSibling() == aEndChild;
InsertionPoint insertion;
if (isSingleInsert) {
// See if we have a Shadow DOM insertion point. If so, then that's our real
diff --git a/testing/web-platform/tests/css/CSS2/replace-root-with-trailing-comment-crash.html b/testing/web-platform/tests/css/CSS2/replace-root-with-trailing-comment-crash.html
@@ -0,0 +1,10 @@
+<html>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2008590">
+<script>
+document.addEventListener("DOMContentLoaded", () => {
+ document.documentElement.replaceWith(a)
+})
+</script>
+<dl id="a">a</dl>
+</html>
+<!-- This comment is needed to trigger the crash -->