WebKit Bugzilla
Attachment 357478 Details for
Bug 157437
: offsetLeft and offsetParent should adjust across shadow boundaries
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Fixes the implementation
bug-157437-20181217143905.patch (text/plain), 24.22 KB, created by
Ryosuke Niwa
on 2018-12-17 14:39:06 PST
(
hide
)
Description:
Fixes the implementation
Filename:
MIME Type:
Creator:
Ryosuke Niwa
Created:
2018-12-17 14:39:06 PST
Size:
24.22 KB
patch
obsolete
>Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 239096) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,42 @@ >+2018-12-17 Ryosuke Niwa <rniwa@webkit.org> >+ >+ offsetLeft and offsetParent should adjust across shadow boundaries >+ https://bugs.webkit.org/show_bug.cgi?id=157437 >+ <rdar://problem/26154021> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Updates our implementation of offsetLeft, offsetTop, and offsetParent to match the latest discussion in CSS WG. >+ See https://github.com/w3c/webcomponents/issues/497 and https://github.com/w3c/webcomponents/issues/763 >+ >+ The latest consensus is to use the retargeting algorithm (https://dom.spec.whatwg.org/#retarget). In practice, >+ this would mean that we need to keep walking up the offset parent ancestors until we find the one which is in >+ the same tree as a shadow-inclusive ancestor of the context object. >+ >+ For example, if a node (the context object of offsetTop, offsetLeft, offsetParent) was assigned to a slot inside >+ a shadow tree and its offset parent was in the shadow tree, we need to walk up to its offset parent, and then its >+ offset parent, etc... until we find the offset parent which is in the same tree as the context object. >+ >+ Note that it's possible that the context object is inside a shadow tree which does not have its own offset parent. >+ (e.g. all elements have position: static) For this reason, we need to consider not just offset parent in the same >+ tree as the context object but as well as any offset parent which is in ancestor trees of the context objects. >+ >+ Test: fast/shadow-dom/offsetParent-across-shadow-boundaries.html >+ >+ * dom/Element.cpp: >+ (WebCore::adjustOffsetForZoomAndSubpixelLayout): Extracted to share code between offsetLeft and offsetTop. >+ (WebCore::collectAncestorTreeScopeAsHashSet): Added. >+ (WebCore::Element::offsetLeftForBindings): Added. Sums up offsetLeft's until it finds the first offset parent >+ which is a shadow-including ancestor (https://dom.spec.whatwg.org/#concept-shadow-including-ancestor). >+ (WebCore::Element::offsetLeft): Now uses adjustOffsetForZoomAndSubpixelLayout. >+ (WebCore::Element::offsetTopForBindings): Added. Like offsetLeftForBindings, this function sums up offsetTop's >+ until it finds the first offset parent which is a shadow-including ancestor. >+ (WebCore::Element::offsetTop): Now uses adjustOffsetForZoomAndSubpixelLayout. >+ (WebCore::Element::offsetParentForBindings): Renamed from bindingsOffsetParent to be consistent with other >+ functions meant to be used for bindings code. >+ * dom/Element.h: >+ * html/HTMLElement.idl: >+ > 2018-12-10 Ryosuke Niwa <rniwa@webkit.org> > > connectedCallback is invoked during the removal of the element inside another element's connectedCallback >Index: Source/WebCore/dom/Element.cpp >=================================================================== >--- Source/WebCore/dom/Element.cpp (revision 239095) >+++ Source/WebCore/dom/Element.cpp (working copy) >@@ -883,27 +883,79 @@ static double convertToNonSubpixelValueI > return subpixelMetricsEnabled(document) ? value : roundStrategy == Round ? round(value) : floor(value); > } > >-double Element::offsetLeft() >+static double adjustOffsetForZoomAndSubpixelLayout(RenderBoxModelObject* renderer, const LayoutUnit& offset) >+{ >+ LayoutUnit offsetLeft = subpixelMetricsEnabled(renderer->document()) ? offset : LayoutUnit(roundToInt(offset)); >+ double zoomFactor = 1; >+ double offsetLeftAdjustedWithZoom = adjustForLocalZoom(offsetLeft, *renderer, zoomFactor); >+ return convertToNonSubpixelValueIfNeeded(offsetLeftAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round); >+} >+ >+static HashSet<TreeScope*> collectAncestorTreeScopeAsHashSet(Node& node) >+{ >+ HashSet<TreeScope*> ancestors; >+ for (auto* currentScope = &node.treeScope(); currentScope; currentScope = currentScope->parentTreeScope()) >+ ancestors.add(currentScope); >+ return ancestors; >+} >+ >+double Element::offsetLeftForBindings() > { > document().updateLayoutIgnorePendingStylesheets(); >- if (RenderBoxModelObject* renderer = renderBoxModelObject()) { >- LayoutUnit offsetLeft = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetLeft() : LayoutUnit(roundToInt(renderer->offsetLeft())); >- double zoomFactor = 1; >- double offsetLeftAdjustedWithZoom = adjustForLocalZoom(offsetLeft, *renderer, zoomFactor); >- return convertToNonSubpixelValueIfNeeded(offsetLeftAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round); >+ >+ auto parent = makeRefPtr(offsetParent()); >+ if (!parent || !parent->isInShadowTree()) >+ return offsetLeft(); >+ >+ ASSERT(&parent->document() == &document()); >+ if (&parent->treeScope() == &treeScope()) >+ return offsetLeft(); >+ >+ double offset = offsetLeft(); >+ auto ancestorTreeScopes = collectAncestorTreeScopeAsHashSet(*this); >+ while (parent && !ancestorTreeScopes.contains(&parent->treeScope())) { >+ offset += parent->offsetLeft(); >+ parent = parent->offsetParent(); > } >+ >+ return offset; >+} >+ >+double Element::offsetLeft() >+{ >+ document().updateLayoutIgnorePendingStylesheets(); >+ if (RenderBoxModelObject* renderer = renderBoxModelObject()) >+ return adjustOffsetForZoomAndSubpixelLayout(renderer, renderer->offsetLeft()); > return 0; > } > >-double Element::offsetTop() >+double Element::offsetTopForBindings() > { > document().updateLayoutIgnorePendingStylesheets(); >- if (RenderBoxModelObject* renderer = renderBoxModelObject()) { >- LayoutUnit offsetTop = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetTop() : LayoutUnit(roundToInt(renderer->offsetTop())); >- double zoomFactor = 1; >- double offsetTopAdjustedWithZoom = adjustForLocalZoom(offsetTop, *renderer, zoomFactor); >- return convertToNonSubpixelValueIfNeeded(offsetTopAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round); >+ >+ auto parent = makeRefPtr(offsetParent()); >+ if (!parent || !parent->isInShadowTree()) >+ return offsetTop(); >+ >+ ASSERT(&parent->document() == &document()); >+ if (&parent->treeScope() == &treeScope()) >+ return offsetTop(); >+ >+ double offset = offsetTop(); >+ auto ancestorTreeScopes = collectAncestorTreeScopeAsHashSet(*this); >+ while (parent && !ancestorTreeScopes.contains(&parent->treeScope())) { >+ offset += parent->offsetTop(); >+ parent = parent->offsetParent(); > } >+ >+ return offset; >+} >+ >+double Element::offsetTop() >+{ >+ document().updateLayoutIgnorePendingStylesheets(); >+ if (RenderBoxModelObject* renderer = renderBoxModelObject()) >+ return adjustOffsetForZoomAndSubpixelLayout(renderer, renderer->offsetTop()); > return 0; > } > >@@ -927,12 +979,14 @@ double Element::offsetHeight() > return 0; > } > >-Element* Element::bindingsOffsetParent() >+Element* Element::offsetParentForBindings() > { > Element* element = offsetParent(); > if (!element || !element->isInShadowTree()) > return element; >- return element->containingShadowRoot()->mode() == ShadowRootMode::UserAgent ? nullptr : element; >+ while (element && !isDescendantOrShadowDescendantOf(&element->rootNode())) >+ element = element->offsetParent(); >+ return element; > } > > Element* Element::offsetParent() >Index: Source/WebCore/dom/Element.h >=================================================================== >--- Source/WebCore/dom/Element.h (revision 239095) >+++ Source/WebCore/dom/Element.h (working copy) >@@ -156,7 +156,9 @@ public: > WEBCORE_EXPORT void scrollByLines(int lines); > WEBCORE_EXPORT void scrollByPages(int pages); > >+ WEBCORE_EXPORT double offsetLeftForBindings(); > WEBCORE_EXPORT double offsetLeft(); >+ WEBCORE_EXPORT double offsetTopForBindings(); > WEBCORE_EXPORT double offsetTop(); > WEBCORE_EXPORT double offsetWidth(); > WEBCORE_EXPORT double offsetHeight(); >@@ -165,7 +167,7 @@ public: > > // FIXME: Replace uses of offsetParent in the platform with calls > // to the render layer and merge bindingsOffsetParent and offsetParent. >- WEBCORE_EXPORT Element* bindingsOffsetParent(); >+ WEBCORE_EXPORT Element* offsetParentForBindings(); > > const Element* rootElement() const; > >Index: Source/WebCore/html/HTMLElement.idl >=================================================================== >--- Source/WebCore/html/HTMLElement.idl (revision 239095) >+++ Source/WebCore/html/HTMLElement.idl (working copy) >@@ -52,9 +52,9 @@ > readonly attribute boolean isContentEditable; > > // Extensions from CSSOM-view specification (https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface). >- [ImplementedAs=bindingsOffsetParent] readonly attribute Element? offsetParent; >- readonly attribute double offsetTop; // FIXME: Should be of type long. >- readonly attribute double offsetLeft; // FIXME: Should be of type long. >+ [ImplementedAs=offsetParentForBindings] readonly attribute Element? offsetParent; >+ [ImplementedAs=offsetTopForBindings] readonly attribute double offsetTop; // FIXME: Should be of type long. >+ [ImplementedAs=offsetLeftForBindings] readonly attribute double offsetLeft; // FIXME: Should be of type long. > readonly attribute double offsetWidth; // FIXME: Should be of type long. > readonly attribute double offsetHeight; // FIXME: Should be of type long. > >Index: Source/WebKitLegacy/mac/ChangeLog >=================================================================== >--- Source/WebKitLegacy/mac/ChangeLog (revision 239289) >+++ Source/WebKitLegacy/mac/ChangeLog (working copy) >@@ -1,3 +1,18 @@ >+2018-12-17 Ryosuke Niwa <rniwa@webkit.org> >+ >+ offsetLeft and offsetParent should adjust across shadow boundaries >+ https://bugs.webkit.org/show_bug.cgi?id=157437 >+ <rdar://problem/26154021> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Use *forBindings variants of offsetLeft, offsetTop, and offsetParent. >+ >+ * DOM/DOMElement.mm: >+ (-[DOMElement offsetLeft]): >+ (-[DOMElement offsetTop]): >+ (-[DOMElement offsetParent]): >+ > 2018-12-17 Zalan Bujtas <zalan@apple.com> > > Unreviewed build fix. >Index: Source/WebKitLegacy/mac/DOM/DOMElement.mm >=================================================================== >--- Source/WebKitLegacy/mac/DOM/DOMElement.mm (revision 239095) >+++ Source/WebKitLegacy/mac/DOM/DOMElement.mm (working copy) >@@ -81,13 +81,13 @@ - (DOMCSSStyleDeclaration *)style > - (int)offsetLeft > { > WebCore::JSMainThreadNullState state; >- return unwrap(*self).offsetLeft(); >+ return unwrap(*self).offsetLeftForBindings(); > } > > - (int)offsetTop > { > WebCore::JSMainThreadNullState state; >- return unwrap(*self).offsetTop(); >+ return unwrap(*self).offsetTopForBindings(); > } > > - (int)offsetWidth >@@ -165,7 +165,7 @@ - (int)scrollHeight > - (DOMElement *)offsetParent > { > WebCore::JSMainThreadNullState state; >- return kit(unwrap(*self).bindingsOffsetParent()); >+ return kit(unwrap(*self).offsetParentForBindings()); > } > > - (NSString *)innerHTML >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 239096) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,16 @@ >+2018-12-17 Ryosuke Niwa <rniwa@webkit.org> >+ >+ offsetLeft and offsetParent should adjust across shadow boundaries >+ https://bugs.webkit.org/show_bug.cgi?id=157437 >+ <rdar://problem/26154021> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Added a W3C style testharness.js test. >+ >+ * fast/shadow-dom/offsetParent-across-shadow-boundaries-expected.txt: Added. >+ * fast/shadow-dom/offsetParent-across-shadow-boundaries.html: Added. >+ > 2018-12-10 Ryosuke Niwa <rniwa@webkit.org> > > connectedCallback is invoked during the removal of the element inside another element's connectedCallback >Index: LayoutTests/fast/shadow-dom/offsetParent-across-shadow-boundaries-expected.txt >=================================================================== >--- LayoutTests/fast/shadow-dom/offsetParent-across-shadow-boundaries-expected.txt (nonexistent) >+++ LayoutTests/fast/shadow-dom/offsetParent-across-shadow-boundaries-expected.txt (working copy) >@@ -0,0 +1,18 @@ >+ >+PASS offsetParent must return the offset parent in the same shadow tree of open mode >+PASS offsetParent must return the offset parent in the same shadow tree of closed mode >+PASS offsetParent must return the offset parent in the same shadow tree of open mode even when nested >+PASS offsetParent must return the offset parent in the same shadow tree of closed mode even when nested >+PASS offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of open mode >+PASS offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of closed mode >+PASS offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of open mode >+PASS offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of closed mode >+PASS offsetParent must skip offset parents of an element when the context object is assigned to a slot in nested shadow trees of open mode >+PASS offsetParent must skip offset parents of an element when the context object is assigned to a slot in nested shadow trees of closed mode >+PASS offsetParent must find the first offset parent which is a shadow-including ancestor of the context object even some shadow tree of open mode did not have any offset parent >+PASS offsetParent must find the first offset parent which is a shadow-including ancestor of the context object even some shadow tree of closed mode did not have any offset parent >+PASS offsetParent must return null on a child element of a shadow host for the shadow tree in open mode which is not assigned to any slot >+PASS offsetParent must return null on a child element of a shadow host for the shadow tree in closed mode which is not assigned to any slot >+PASS offsetParent must return null on a child element of a shadow host for the shadow tree in open mode which is not in the flat tree >+PASS offsetParent must return null on a child element of a shadow host for the shadow tree in closed mode which is not in the flat tree >+ >Index: LayoutTests/fast/shadow-dom/offsetParent-across-shadow-boundaries.html >=================================================================== >--- LayoutTests/fast/shadow-dom/offsetParent-across-shadow-boundaries.html (nonexistent) >+++ LayoutTests/fast/shadow-dom/offsetParent-across-shadow-boundaries.html (working copy) >@@ -0,0 +1,190 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> >+<meta name="assert" content="offsetParent should only return nodes that are shadow including ancestor"> >+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent"> >+<link rel="help" href="https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor"> >+<script src="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="resources/event-path-test-helpers.js"></script> >+</head> >+<body> >+<div id="log"></div> >+<div id="container" style="position: relative"></div> >+<script> >+ >+const container = document.getElementById('container'); >+ >+function testOffsetParentInShadowTree(mode) { >+ test(function () { >+ const host = document.createElement('div'); >+ container.appendChild(host); >+ this.add_cleanup(() => host.remove()); >+ const shadowRoot = host.attachShadow({mode}); >+ shadowRoot.innerHTML = '<div id="relativeParent" style="position: relative; padding-left: 100px; padding-top: 70px;"><div id="target"></div></div>'; >+ const relativeParent = shadowRoot.getElementById('relativeParent'); >+ >+ assert_true(relativeParent instanceof HTMLDivElement); >+ const target = shadowRoot.getElementById('target'); >+ assert_equals(target.offsetParent, relativeParent); >+ assert_equals(target.offsetLeft, 100); >+ assert_equals(target.offsetTop, 70); >+ }, `offsetParent must return the offset parent in the same shadow tree of ${mode} mode`); >+} >+ >+testOffsetParentInShadowTree('open'); >+testOffsetParentInShadowTree('closed'); >+ >+function testOffsetParentInNestedShadowTrees(mode) { >+ test(function () { >+ const outerHost = document.createElement('section'); >+ container.appendChild(outerHost); >+ this.add_cleanup(() => outerHost.remove()); >+ const outerShadow = outerHost.attachShadow({mode}); >+ outerShadow.innerHTML = '<section id="outerParent" style="position: absolute; top: 50px; left: 50px;"></section>'; >+ >+ const innerHost = document.createElement('div'); >+ outerShadow.firstChild.appendChild(innerHost); >+ const innerShadow = innerHost.attachShadow({mode}); >+ innerShadow.innerHTML = '<div id="innerParent" style="position: relative; padding-left: 60px; padding-top: 40px;"><div id="target"></div></div>'; >+ const innerParent = innerShadow.getElementById('innerParent'); >+ >+ const target = innerShadow.getElementById('target'); >+ assert_true(innerParent instanceof HTMLDivElement); >+ assert_equals(target.offsetParent, innerParent); >+ assert_equals(target.offsetLeft, 60); >+ assert_equals(target.offsetTop, 40); >+ >+ outerHost.remove(); >+ }, `offsetParent must return the offset parent in the same shadow tree of ${mode} mode even when nested`); >+} >+ >+testOffsetParentInNestedShadowTrees('open'); >+testOffsetParentInNestedShadowTrees('closed'); >+ >+function testOffsetParentOnElementAssignedToSlotInsideOffsetParent(mode) { >+ test(function () { >+ const host = document.createElement('div'); >+ host.innerHTML = '<div id="target"></div>' >+ container.appendChild(host); >+ this.add_cleanup(() => host.remove()); >+ const shadowRoot = host.attachShadow({mode}); >+ shadowRoot.innerHTML = '<div style="position: relative; padding-left: 85px; padding-top: 45px;"><slot></slot></div>'; >+ const target = host.querySelector('#target'); >+ assert_equals(target.offsetParent, container); >+ assert_equals(target.offsetLeft, 85); >+ assert_equals(target.offsetTop, 45); >+ }, `offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of ${mode} mode`); >+} >+ >+testOffsetParentOnElementAssignedToSlotInsideOffsetParent('open'); >+testOffsetParentOnElementAssignedToSlotInsideOffsetParent('closed'); >+ >+function testOffsetParentOnElementAssignedToSlotInsideNestedOffsetParents(mode) { >+ test(function () { >+ const host = document.createElement('div'); >+ host.innerHTML = '<div id="target" style="border:solid 1px blue;">hi</div>'; >+ const previousBlock = document.createElement('div'); >+ previousBlock.style.height = '12px'; >+ container.append(previousBlock, host); >+ this.add_cleanup(() => container.innerHTML = ''); >+ const shadowRoot = host.attachShadow({mode}); >+ shadowRoot.innerHTML = '<section style="position: relative; margin-left: 20px; margin-top: 100px; background: #ccc"><div style="position: absolute; top: 10px; left: 10px;"><slot></slot></div></section>'; >+ const target = host.querySelector('#target'); >+ assert_equals(target.offsetParent, container); >+ assert_equals(target.offsetLeft, 30); >+ assert_equals(target.offsetTop, 122); >+ }, `offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of ${mode} mode`); >+} >+ >+testOffsetParentOnElementAssignedToSlotInsideNestedOffsetParents('open'); >+testOffsetParentOnElementAssignedToSlotInsideNestedOffsetParents('closed'); >+ >+function testOffsetParentOnElementAssignedToSlotInsideNestedShadowTrees(mode) { >+ test(function () { >+ const outerHost = document.createElement('section'); >+ outerHost.innerHTML = '<div id="target"></div>'; >+ container.appendChild(outerHost); >+ this.add_cleanup(() => outerHost.remove()); >+ const outerShadow = outerHost.attachShadow({mode}); >+ outerShadow.innerHTML = '<section style="position: absolute; top: 40px; left: 50px;"><div id="innerHost"><slot></slot></div></section>'; >+ >+ const innerShadow = outerShadow.getElementById('innerHost').attachShadow({mode}); >+ innerShadow.innerHTML = '<div style="position: absolute; top: 200px; margin-left: 100px;"><slot></slot></div>'; >+ >+ const target = outerHost.querySelector('#target'); >+ assert_equals(target.offsetParent, container); >+ assert_equals(target.offsetLeft, 150); >+ assert_equals(target.offsetTop, 240); >+ outerHost.remove(); >+ }, `offsetParent must skip offset parents of an element when the context object is assigned to a slot in nested shadow trees of ${mode} mode`); >+} >+ >+testOffsetParentOnElementAssignedToSlotInsideNestedShadowTrees('open'); >+testOffsetParentOnElementAssignedToSlotInsideNestedShadowTrees('closed'); >+ >+function testOffsetParentOnElementInsideShadowTreeWithoutOffsetParent(mode) { >+ test(function () { >+ const outerHost = document.createElement('section'); >+ container.appendChild(outerHost); >+ this.add_cleanup(() => outerHost.remove()); >+ const outerShadow = outerHost.attachShadow({mode}); >+ outerShadow.innerHTML = '<div id="innerHost"><div id="target"></div></div>'; >+ >+ const innerShadow = outerShadow.getElementById('innerHost').attachShadow({mode}); >+ innerShadow.innerHTML = '<div style="position: absolute; top: 23px; left: 24px;"><slot></slot></div>'; >+ >+ const target = outerShadow.querySelector('#target'); >+ assert_equals(target.offsetParent, container); >+ assert_equals(target.offsetLeft, 24); >+ assert_equals(target.offsetTop, 23); >+ }, `offsetParent must find the first offset parent which is a shadow-including ancestor of the context object even some shadow tree of ${mode} mode did not have any offset parent`); >+} >+ >+testOffsetParentOnElementInsideShadowTreeWithoutOffsetParent('open'); >+testOffsetParentOnElementInsideShadowTreeWithoutOffsetParent('closed'); >+ >+function testOffsetParentOnUnassignedChild(mode) { >+ test(function () { >+ const host = document.createElement('section'); >+ host.innerHTML = '<div id="target"></div>'; >+ this.add_cleanup(() => host.remove()); >+ container.appendChild(host); >+ const shadowRoot = host.attachShadow({mode}); >+ shadowRoot.innerHTML = '<section style="position: absolute; top: 50px; left: 50px;">content</section>'; >+ const target = host.querySelector('#target'); >+ assert_equals(target.offsetParent, null); >+ assert_equals(target.offsetLeft, 0); >+ assert_equals(target.offsetTop, 0); >+ }, `offsetParent must return null on a child element of a shadow host for the shadow tree in ${mode} mode which is not assigned to any slot`); >+} >+ >+testOffsetParentOnUnassignedChild('open'); >+testOffsetParentOnUnassignedChild('closed'); >+ >+function testOffsetParentOnAssignedChildNotInFlatTree(mode) { >+ test(function () { >+ const outerHost = document.createElement('section'); >+ outerHost.innerHTML = '<div id="target"></div>'; >+ container.appendChild(outerHost); >+ this.add_cleanup(() => outerHost.remove()); >+ const outerShadow = outerHost.attachShadow({mode}); >+ outerShadow.innerHTML = '<div id="innerHost"><div style="position: absolute; top: 50px; left: 50px;"><slot></slot></div></div>'; >+ >+ const innerShadow = outerShadow.getElementById('innerHost').attachShadow({mode}); >+ innerShadow.innerHTML = '<div>content</div>'; >+ >+ const target = outerHost.querySelector('#target'); >+ assert_equals(target.offsetParent, null); >+ assert_equals(target.offsetLeft, 0); >+ assert_equals(target.offsetTop, 0); >+ }, `offsetParent must return null on a child element of a shadow host for the shadow tree in ${mode} mode which is not in the flat tree`); >+} >+ >+testOffsetParentOnAssignedChildNotInFlatTree('open'); >+testOffsetParentOnAssignedChildNotInFlatTree('closed'); >+ >+</script> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 157437
:
357294
|
357478
|
357503