Bug 1404789: Get the insertion point right when reconstructing direct children of a shadow root. r=bz
MozReview-Commit-ID: 2Xlke5ujt2Q
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7780,18 +7780,20 @@ nsCSSFrameConstructor::ContentAppended(n
}
// Create some new frames
//
// We use the provided tree match context, or create a new one on the fly
// otherwise.
Maybe<TreeMatchContext> matchContext;
if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
+ // We use GetParentElementCrossingShadowRoot to handle the case where
+ // aContainer is a ShadowRoot.
matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
- matchContext->InitAncestors(aContainer->AsElement());
+ matchContext->InitAncestors(aFirstNewContent->GetParentElementCrossingShadowRoot());
}
nsFrameConstructorState state(mPresShell,
matchContext.ptrOr(aProvidedTreeMatchContext),
GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
GetAbsoluteContainingBlock(parentFrame, ABS_POS),
containingBlock);
LayoutFrameType frameType = parentFrame->Type();
@@ -8121,28 +8123,32 @@ nsCSSFrameConstructor::ContentRangeInser
return;
}
nsContainerFrame* parentFrame = GetContentInsertionFrameFor(aContainer);
// The xbl:children element won't have a frame, but default content can have the children as
// a parent. While its uncommon to change the structure of the default content itself, a label,
// for example, can be reframed by having its value attribute set or removed.
- if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
+ if (!parentFrame &&
+ !(aContainer->IsActiveChildrenElement() ||
+ ShadowRoot::FromNode(aContainer))) {
// We're punting on frame construction because there's no container frame.
// The Servo-backed style system handles this case like the lazy frame
// construction case, except when we're already constructing frames, in
// which case we shouldn't need to do anything else.
if (aContainer->IsStyledByServo() &&
aInsertionKind == InsertionKind::Async) {
LazilyStyleNewChildRange(aStartChild, aEndChild);
}
return;
}
+ MOZ_ASSERT_IF(ShadowRoot::FromNode(aContainer), !parentFrame);
+
// Otherwise, we've got parent content. Find its frame.
NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer ||
GetDisplayContentsStyleFor(aContainer), "New XBL code is possibly wrong!");
if (aInsertionKind == InsertionKind::Async &&
MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
if (aContainer->IsStyledByServo()) {
LazilyStyleNewChildRange(aStartChild, aEndChild);
@@ -8246,18 +8252,20 @@ nsCSSFrameConstructor::ContentRangeInser
RecreateFramesForContent(insertion.mParentFrame->GetContent(),
aInsertionKind);
LAYOUT_PHASE_TEMP_REENTER();
return;
}
Maybe<TreeMatchContext> matchContext;
if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
+ // We use GetParentElementCrossingShadowRoot to handle the case where
+ // aContainer is a ShadowRoot.
matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
- matchContext->InitAncestors(aContainer ? aContainer->AsElement() : nullptr);
+ matchContext->InitAncestors(aStartChild->GetParentElementCrossingShadowRoot());
}
nsFrameConstructorState state(mPresShell,
matchContext.ptrOr(aProvidedTreeMatchContext),
GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
GetFloatContainingBlock(insertion.mParentFrame),
do_AddRef(aFrameState));
@@ -9531,18 +9539,21 @@ nsCSSFrameConstructor::GetInsertionPoint
// We've got an explicit insertion child. Check to see if it's
// anonymous.
if (aChild->GetBindingParent() == aContainer) {
// This child content is anonymous. Don't use the insertion
// point, since that's only for the explicit kids.
return InsertionPoint(GetContentInsertionFrameFor(aContainer), aContainer);
}
- if (nsContentUtils::HasDistributedChildren(aContainer)) {
- // The container distributes nodes, use the frame of the flattened tree parent.
+ if (nsContentUtils::HasDistributedChildren(aContainer) ||
+ ShadowRoot::FromNode(aContainer)) {
+ // The container distributes nodes or is a shadow root, use the frame of
+ // the flattened tree parent.
+ //
// It may be the case that the node is distributed but not matched to any
// insertion points, so there is no flattened parent.
nsIContent* flattenedParent = aChild->GetFlattenedTreeParent();
if (flattenedParent) {
return InsertionPoint(GetContentInsertionFrameFor(flattenedParent),
flattenedParent);
}
return InsertionPoint();
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webcomponents/reframe-shadow-child-1.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<template id="tmpl">
+ <div style="display: table">
+ Some text
+ <span style="display: table-cell">something</span>
+ More text
+ </div>
+</template>
+<div id="host"></div>
+<script>
+ let shadowRoot = document.getElementById("host").createShadowRoot();
+ let tmpl = document.getElementById("tmpl");
+ shadowRoot.appendChild(document.importNode(tmpl.content, true));
+ document.body.offsetTop;
+ shadowRoot.firstElementChild.querySelector("span").remove();
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webcomponents/reframe-shadow-child-2.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<template id="tmpl">
+ <div style="display: block">
+ Some text
+ More text
+ </div>
+</template>
+<div id="host"></div>
+<script>
+ let shadowRoot = document.getElementById("host").createShadowRoot();
+ let tmpl = document.getElementById("tmpl");
+ shadowRoot.appendChild(document.importNode(tmpl.content, true));
+ document.body.offsetTop;
+ shadowRoot.firstElementChild.style.display = "table";
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webcomponents/reframe-shadow-child-ref.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<div style="display: table">
+ Some text
+ More text
+</div>
--- a/layout/reftests/webcomponents/reftest.list
+++ b/layout/reftests/webcomponents/reftest.list
@@ -8,8 +8,10 @@ pref(dom.webcomponents.enabled,true) ==
pref(dom.webcomponents.enabled,true) == fallback-content-1.html fallback-content-1-ref.html
pref(dom.webcomponents.enabled,true) == remove-insertion-point-1.html remove-insertion-point-1-ref.html
pref(dom.webcomponents.enabled,true) == nested-insertion-point-1.html nested-insertion-point-1-ref.html
pref(dom.webcomponents.enabled,true) == update-dist-node-descendants-1.html update-dist-node-descendants-1-ref.html
pref(dom.webcomponents.enabled,true) fuzzy-if(Android,2,7) == input-transition-1.html input-transition-1-ref.html
pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-1.html dynamic-insertion-point-distribution-1-ref.html
pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-2.html dynamic-insertion-point-distribution-2-ref.html
pref(dom.webcomponents.enabled,true) == remove-append-shadow-host-1.html remove-append-shadow-host-1-ref.html
+pref(dom.webcomponents.enabled,true) == reframe-shadow-child-1.html reframe-shadow-child-ref.html
+pref(dom.webcomponents.enabled,true) == reframe-shadow-child-2.html reframe-shadow-child-ref.html