New issue
Advanced search Search tips

Issue 843215 link

Starred by 5 users

Issue metadata

Status: Fixed
Owner:
Closed: Jul 24
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Windows , Mac
Pri: 2
Type: Bug-Regression



Sign in to add a comment

document.elementsFromPoint changed in Chrome 66 to include parent elements of shadow trees

Reported by ho...@marcysutton.com, May 15 2018

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36

Steps to reproduce the problem:
1. Assemble a stack of elements including nodes from shadow trees using document.elementsFromPoint.
2. Compare to Chrome 65, where the stack returned did not include parent nodes.
3. In Chrome 66, observe an infinite loop when you try to run the same code.

What is the expected behavior?
Chrome should not get into an infinite loop when assembling a stack of shadow and light dom elements. Changes to document.elementsFromPoint should be documented and communicated to developers to prevent such failures from occurring in code that uses Shadow DOM.

What went wrong?
There was a change to document.elementsFromPoint in Chrome 66 that started throwing an infinite loop in axe-core, the accessibility testing library powering Lighthouse. Previously, calling elementsFromPoint on a shadow dom tree would only return nodes from that tree. In Chrome 66, it started also returning parent nodes, so the logic to combine the two stacks caused an infinite loop. Because not every user will be in Chrome 66 necessarily, we had to update our code to work with both browser versions by bailing out if it gets put into such a loop.

Did this work before? Yes Chrome 65

Does this work in other browsers? Yes

Chrome version: 66.0.3359.170  Channel: stable
OS Version: OS X 10.13.4
Flash Version: 

You can observe the bug report in axe-core here: https://github.com/dequelabs/axe-core/issues/856

You can also review the PR we included to stop the infinite loop here: 
https://github.com/dequelabs/axe-core/pull/861
 
index.html
3.2 KB View Download
One comment about the "does this work in other browsers": there was no "N/A" option to specify a lack of relevance in other browsers, as only Chromium has native support for Shadow DOM. It would be polyfilled in non-chromium browsers.
Also, the motivation for this kind of element stack assembly is color contrast evaluation.
Labels: Needs-Bisect Needs-Triage-M66

Comment 4 by hayato@chromium.org, May 16 2018

Labels: -Pri-2 Pri-1
Owner: rakina@chromium.org
Status: Assigned (was: Unconfirmed)
This might be related: https://www.chromestatus.com/feature/6317470654660608

rakina@, could you take a look?
Cc: vamshi.kommuri@chromium.org
Labels: Triaged-ET Needs-Feedback
Tried checking the issue on reported chrome version 66.0.3359.170 using Mac 10.13.1 with the below mentioned steps.
1. Launched chrome
2. Downloaded Index.html and opened it in a new tab.
3. Observed "Text" in black background strip.
Attaching the screen shot for reference.

@Reporter: We didn't see/observe chrome getting into infinite loop, As we are not very sure about the steps followed by us are correct in order to reproduce the issue, It would be highly helpful if mentioned the exact steps to be followed. Any further inputs from your end may be helpful.

Thanks!
843215.png
476 KB View Download
Labels: -Needs-Feedback -Needs-Bisect hasbisect-per-revision Target-67 ReleaseBlock-Stable Target-66 M-66 FoundIn-66 FoundIn-67 FoundIn-68 RegressedIn-66 Target-68 OS-Linux OS-Windows
++ Retriaged the issue by considering the console output in Devtools of the Index.html page.

Able to reproduce the issue on reported chrome version 66.0.3359.170 and on the latest canary 68.0.3432.0 using Mac 10.13.1, Ubuntu 14.04 and Windows 10.

Bisect Information:
====================
Last Good Build: 66.0.3331.0
First Bad Build: 66.0.3332.0

You are probably looking for a change made after 531838 (known good), but no later than 531839 (first known bad).

CHANGELOG URL:  https://chromium.googlesource.com/chromium/src/+log/3bc515d57274da3066b7122f6dcf47dc45af5123..bb3517a95aa758711ac11927e8f8ebf44f6a272b
Suspecting: https://chromium.googlesource.com/chromium/src/+/bb3517a95aa758711ac11927e8f8ebf44f6a272b
Review URL: https://chromium-review.googlesource.com/880741

Note: As this seems to be a recent regression, hence adding RB-Stable. Please remove if not applicable.

Thanks!
It does occur if you open the devtools console, my apologies for forgetting that step. Thanks for the quick replies!

Comment 8 by rakina@chromium.org, May 16 2018

Cc: hayato@chromium.org
Hi there, thanks for filing the bug. Sorry for the confusion the change is making!

It looks like elementsFromPoint did in fact only return nodes from its scope (aka under the same shadow root only) before, and now it can cross shadow boundary up until the document element. Sorry I did not notice the change in behavior, should've checked that first (there were no tests for elementsfrompoint on shadowroot before, I made some tests that expected the new behavior). 

I guess the question now is whether we should change it back to its previous behavior. There is no formal spec yet for the shadow root case, we only have the one for document: https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint and a statement in https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin, so I don't know whether ShadowRoot.elementsFromPoint only return elements in the shadow root's scope, or return everything as it is currently. @hayato, what do you think?


Comment 9 by hayato@chromium.org, May 17 2018

It looks the current behavior is collect, from the spec's perspective.

> I guess the question now is whether we should change it back to its previous behavior. 

It's always difficult question, however, in general, we should be careful and should wait for more breakage reports.

If there are no other breakage reports from other sites, and axe-core can be fixed (I am totally aware this is super painful and super-frustrating for users), maybe we shouldn't revert this change.

Comment 10 by phistuck@gmail.com, May 17 2018

#8, #9 - if the behavior is not clear, please, file an issue (a link here would be nice) against the specification so no one else has to guess...
As this is regressed in M66 stable and we're very close to M67 stable promotion,  we won't consider this as M67 Stable blocker. Pls let us know ASAP if there is any concern here. Thank you.
Labels: -Pri-1 -ReleaseBlock-Stable Pri-2
> #8, #9 - if the behavior is not clear, please, file an issue (a link here would be nice) against the specification so no one else has to guess...

FYI. There is an filed issue on CSSOM view: https://github.com/w3c/csswg-drafts/issues/556#issuecomment-265371567


Apart from the topic on the issue, it looks clear to me that we should use retargeting algorithm here, according to note in the Shadow DOM spec:

> Regarding elementFromPoint and elementsFromPoints, they should return the result of running the retargeting algorithm with context object and the original result as input.

Comment 14 by foooo...@gmail.com, May 20 2018

My Chrome extension "View background image" has the same problem.
https://github.com/foooomio/view-background-image/issues/12

I disagree with the current behaivor. It is hard to tell inner elements from outer elements of Shadow DOM.

For example, pick up my extension's processing flow:

1. Get the elements under mouse cursor by document.elementsFromPoint.
2. For each elements, get the background image.
3. If the element has a shadowRoot, apply this flow to it in place of document.

The current behaivor causes an infinite loop at 3. For details, please see the code.
https://github.com/foooomio/view-background-image/blob/bc04f7a529552b73f3fcbbbf6598fed2459466af/src/content.js

With the previous behaivor, we can apply functions to either document or shadowRoot recursively. At present, we need workaround only for Shadow DOM. I don't think it is profitable.


BTW, the result of shadowRoot.elementsFromPoint doesn't contain the whole of document.elementsFromPoint, such as html element. Is it correct?
@ #14, 

Thanks for commenting. Can you give an example of cases where document.elementsFromPoint don't match shadowRoot.elementsFromPoint (excluding nodes in the shadow tree)?

That's not expected from our WPT in https://cs.chromium.org/chromium/src/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html?q=third_party/WebKit/LayoutTests/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html&sq=package:chromium&g=0&l=1

Comment 16 by foooo...@gmail.com, May 24 2018

@ #15,

Access https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/#ex3aNameTag and run codes below on console. You will see shadowRoot.elementsFromPoint doesn't return html element.

var element = $('#ex3aNameTag')
var rect = element.getBoundingClientRect()
document.elementsFromPoint(rect.x, rect.y)
element.shadowRoot.elementsFromPoint(rect.x, rect.y)

Anyway, this odd behavior will be resolved if shadowRoot.elementsFromPoint is restored.
@ #16,
Sorry for the long delay in reply!
Thanks for the example case, it really helps. There was a bug in the code that made it that way. I put out a CL (crrev.com/c/1131023)

FYI, the case is special and not covered in the LayoutTests before. The situation is when the HTML element's height is shorter than the position of the hit-tested element so it doesn't get hit-tested. There's additional check for non-shadow root code so it still returns for the non-shadow root case. (I don't know if we actually should return the HTML element in that case, but maybe it's better to follow existing behavior of Document.elementsFromPoint?)
Project Member

Comment 18 by bugdroid1@chromium.org, Jul 11

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/7809be6a01af457d8b17a8b1aa4a98fd3f8dca1b

commit 7809be6a01af457d8b17a8b1aa4a98fd3f8dca1b
Author: Rakina Zata Amni <rakina@chromium.org>
Date: Wed Jul 11 08:07:49 2018

Make ShadowRoot.elementsFromPoint always return document element

Currently in some cases, ShadowRoot.elementsFromPoint may not return
the document element even when Document.elementsFromPoint returns the
document element such as when the document element height is shorter than
the hit-tested element's position. This CL fixes it by removing a check
in TreeScope::ElementsFromHitTestResult.

See example live case detailed in this comment:
https://bugs.chromium.org/p/chromium/issues/detail?id=843215#c16

Bug:  843215 
Change-Id: I5b774d1a091f3c3f72345c55bca188fad309ba58
Reviewed-on: https://chromium-review.googlesource.com/1131023
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: Hayato Ito <hayato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#574104}
[modify] https://crrev.com/7809be6a01af457d8b17a8b1aa4a98fd3f8dca1b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html
[modify] https://crrev.com/7809be6a01af457d8b17a8b1aa4a98fd3f8dca1b/third_party/blink/renderer/core/dom/tree_scope.cc

@ #17,
Thank you for the fix. I also think it's better, aside from whether the behavior of Document.elementsFromPoint is correct or not.

My concern is whether ShadowRoot.elementsFromPoint will get back to the previous behavior or not. Is the current behavior suitable for the retargeting algorithm?
We have no plan on changing the behavior back currently, but I agree that one might expect that shadowRoot.elementsFromPoint only return elements under the shadow root (like shadowRoot.styleSheets) though we also can see that shadowRoot.elementFromPoint might return an element that's not under the shadow root (For example, when a text node is a direct child of a shadow root, it will return the shadow host). 

I suggest you participate in the discussion at https://github.com/w3c/csswg-drafts/issues/556 as the decision of what makes sense might be better discussed there.
foooomio@

You can think the current behavior of {document,shadowroot}.elementsFromPoints as:

- Basically, return all elements in a tree of trees, however, the result should be adjusted so that elements which should not be *visible* from the context object should not be exposed to callers


The current behavior of {document,shadowroot}.elementsFromPoints are NOT:

- Return only elements under the context object's tree.


Regarding https://github.com/foooomio/view-background-image/blob/bc04f7a529552b73f3fcbbbf6598fed2459466af/src/content.js,
you might want to check `element.getRootNode() === shadowRoot` so that it doesn't cause an infinite loop.



Hayato@

Thank you for the advise. It does work well by checking `element.getRootNode()`. I appreciate it.

I understand that {document,shadowroot}.elementsFromPoint are almost the same, except that document's doesn't return elements inside shadow trees because they should not be visible from the outside. Is my understanding correct?
> I understand that {document,shadowroot}.elementsFromPoint are almost the same, except that document's doesn't return elements inside shadow trees because they should not be visible from the outside. Is my understanding correct?

Yes that's correct. Shadow root can see outside up to document root, but document can't see anything in shadow tree.
I got it. Thank you for your kind instruction. The current behavior is reasonable.
Status: Fixed (was: Assigned)
rakina@, I think we can close this issue.
Please feel free to re-open if someone finds any wrong behavior.

Sign in to add a comment