|
|
Created:
5 years, 4 months ago by Yufeng Shen (Slow to review) Modified:
5 years, 4 months ago CC:
blink-reviews, dshwang, slimming-paint-reviews_chromium.org, blink-reviews-paint_chromium.org, majidvp Base URL:
https://chromium.googlesource.com/chromium/blink.git@master Target Ref:
refs/heads/master Project:
blink Visibility:
Public. |
DescriptionFallback to root layer if hit-testing does not hit anything in iframe
Currently we have a hit-testing fallback that if nothing is hit,
consider the root layer (document element) is hit. The fallback is
only for main document, but not iframe. It is not unreasonable that
if the hit point is within the iframe's bound, it should be considered
to hit the iframe's document if it does not hit any other element.
This CL does this modification to the fallback rule.
BUG=508474
Committed: https://src.chromium.org/viewvc/blink?view=rev&revision=201188
Patch Set 1 #
Total comments: 9
Patch Set 2 : address comments #Patch Set 3 : remove "active" hack for wheel event hit-test & using document.documentElement.scrollTop for scroll… #
Total comments: 6
Patch Set 4 : address comments #Patch Set 5 : fix layout test #
Messages
Total messages: 21 (7 generated)
miletus@chromium.org changed reviewers: + dtapuska@chromium.org, rbyers@chromium.org
Thanks Yufeng. This seems reasonable overall, but I think we can go a little further to clean up the behavior a bit. Big picture, saying "we hit the root layer but no specific renderer, so we should fallback to sending the event to the document" seems completely reasonable to me and should be implemented in a general way. But the other stuff about dragging outside the window bounds is sketchy, so ideally would have a separate hack which we work to remove. WDYT? https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1514: // will stop hit testing search, and the result list will be incomplete. So what does this mean for a tap that occurs entirely inside an iframe but outside of any layer? It would be weird if tapping hit through to the parent document but clicking didn't in that case. I assume we wouldn't see a problem today due to our point-based fallback (http://crbug.com/398914). Please add a test for this scenario so that if we ever fix that fallback we'll know we also need to fix this case somehow. https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1516: if (!hitTestLocation.isRectBasedTest() && (request.active() || request.release() || request.move()) && hitTestArea.contains(hitPoint.x(), hitPoint.y()) && isRootLayer()) Can you just avoid checking the hit test flags (release, move active) entirely? Most hit tests should be one of those three, and it's really wrong that we pay attention to the flags at all (again I believe Dave has a bug for this somewhere?). https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1518: } I think you could more clearly separate the confusing mix of hacky heuristics and reasonable behavior here if you reworked the condition as follows: if (!insideLayer && isRootLayer()) { // If we didn't hit any layers but are still inside the document // bounds, then we should fallback to hitting the document. if (hitTestArea.contains(hitPoint.x(), hitPoint.y()) { // Except avoid early termination of rect-based hit test // search in iframe case ... if (!(request.isChildFrameHitTest() && hitTestLocation.isRectBasedTest())) fallback = true; // Mouse dragging outside the main document should also be // delivered to the document // TODO(dtapuska): Capture behavior inconsistent with iframes crbug.com/XXXX } else if ((request.active() || request.release()) && !request.isChildFrameHitTest() { fallback = true; } } If this formulation works, then you can also get rid of the hack Majid added in https://codereview.chromium.org/1210253003/diff/80001/Source/core/input/Event... (but the argument that this mouse-drag specific fallback case belongs in EventHandler, not DeprecatedPaintLayer is still true and maybe something you want to try moving in a subsequent CL).
Dave / Majid, do you have any input? I know you've both looked at this problem more deeply than I have, so I might be over-simplifying it.
https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1514: // will stop hit testing search, and the result list will be incomplete. On 2015/08/17 15:18:29, Rick Byers wrote: > So what does this mean for a tap that occurs entirely inside an iframe but > outside of any layer? It would be weird if tapping hit through to the parent > document but clicking didn't in that case. I assume we wouldn't see a problem > today due to our point-based fallback (http://crbug.com/398914). Please add a > test for this scenario so that if we ever fix that fallback we'll know we also > need to fix this case somehow. ah, right, if the hit-rect (for tap) is totally within the bounds of the iframe, we should also do the fallback. I removed the condition of "!hitTestLocation.isRectBasedTest()", but use "hitTestArea.contains(LayoutRect(hitRect)", which covers both the point based and rect based inclusion test. I dropped the "request.move()" condition, not sure if that will cause any problem. Note: point-based re-hit-test for adjusted position of gesture event would not change the captured frame, I think. Because point-based re-hit-test seems only calling hitTestResultInFrame(), which does not set HitTestRequest::AllowChildFrameContent (hitTestResultAtPoint() does). So if touch adjustment sets the hit-test node to be NodeA in DoucmentA, point-based re-test would not descend into iframes but stick to DocumentA, though NodeA may be changed in the re-test. Anyway, I added a the case of tap and click in the layout test. https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1516: if (!hitTestLocation.isRectBasedTest() && (request.active() || request.release() || request.move()) && hitTestArea.contains(hitPoint.x(), hitPoint.y()) && isRootLayer()) On 2015/08/17 15:18:29, Rick Byers wrote: > Can you just avoid checking the hit test flags (release, move active) entirely? > Most hit tests should be one of those three, and it's really wrong that we pay > attention to the flags at all (again I believe Dave has a bug for this > somewhere?). Done. https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1518: } On 2015/08/17 15:18:29, Rick Byers wrote: > I think you could more clearly separate the confusing mix of hacky heuristics > and reasonable behavior here if you reworked the condition as follows: > > if (!insideLayer && isRootLayer()) { > > // If we didn't hit any layers but are still inside the document > // bounds, then we should fallback to hitting the document. > if (hitTestArea.contains(hitPoint.x(), hitPoint.y()) { > > // Except avoid early termination of rect-based hit test > // search in iframe case ... > if (!(request.isChildFrameHitTest() && > hitTestLocation.isRectBasedTest())) > fallback = true; > > // Mouse dragging outside the main document should also be > // delivered to the document > // TODO(dtapuska): Capture behavior inconsistent with iframes crbug.com/XXXX > } else if ((request.active() || request.release()) && > !request.isChildFrameHitTest() { > fallback = true; > } > } > done. > If this formulation works, then you can also get rid of the hack Majid added in > https://codereview.chromium.org/1210253003/diff/80001/Source/core/input/Event... > (but the argument that this mouse-drag specific fallback case belongs in > EventHandler, not DeprecatedPaintLayer is still true and maybe something you > want to try moving in a subsequent CL). Majid's CL adds a test case where wheel event is outside even the window bounds, which is relying on the "... else if ((request.active() ... " condition to capture but not the condition "if (hitTestArea.contains(LayoutRect(hitRect))" which this CL is focusing on, so I can't really remove the active flag hack for wheel event hit-test.
https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1518: } On 2015/08/18 16:05:21, Yufeng Shen wrote: > On 2015/08/17 15:18:29, Rick Byers wrote: > > I think you could more clearly separate the confusing mix of hacky heuristics > > and reasonable behavior here if you reworked the condition as follows: > > > > if (!insideLayer && isRootLayer()) { > > > > // If we didn't hit any layers but are still inside the document > > // bounds, then we should fallback to hitting the document. > > if (hitTestArea.contains(hitPoint.x(), hitPoint.y()) { > > > > // Except avoid early termination of rect-based hit test > > // search in iframe case ... > > if (!(request.isChildFrameHitTest() && > > hitTestLocation.isRectBasedTest())) > > fallback = true; > > > > // Mouse dragging outside the main document should also be > > // delivered to the document > > // TODO(dtapuska): Capture behavior inconsistent with iframes crbug.com/XXXX > > } else if ((request.active() || request.release()) && > > !request.isChildFrameHitTest() { > > fallback = true; > > } > > } > > > > done. > > > If this formulation works, then you can also get rid of the hack Majid added > in > > > https://codereview.chromium.org/1210253003/diff/80001/Source/core/input/Event... > > (but the argument that this mouse-drag specific fallback case belongs in > > EventHandler, not DeprecatedPaintLayer is still true and maybe something you > > want to try moving in a subsequent CL). > > Majid's CL adds a test case where wheel event is outside even the window bounds, > which is relying on the "... else if ((request.active() ... " condition to > capture but not the condition "if (hitTestArea.contains(LayoutRect(hitRect))" > which this CL is focusing on, so I can't really remove the active flag hack for > wheel event hit-test. I don't think part of the test is important, in fact I'd probably argue it's a bug too (blink shouldn't be getting wheel events outside of the window entirely, and if it does we probably shouldn't be scrolling). So I think you can just update the test to not expect any events in the case where the co-ordinates are entirely outside the wheel. Majid, do you agree?
majidvp@chromium.org changed reviewers: + majidvp@chromium.org
https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1518: } On 2015/08/19 19:23:19, Rick Byers wrote: > On 2015/08/18 16:05:21, Yufeng Shen wrote: > > On 2015/08/17 15:18:29, Rick Byers wrote: > > > I think you could more clearly separate the confusing mix of hacky > heuristics > > > and reasonable behavior here if you reworked the condition as follows: > > > > > > if (!insideLayer && isRootLayer()) { > > > > > > // If we didn't hit any layers but are still inside the document > > > // bounds, then we should fallback to hitting the document. > > > if (hitTestArea.contains(hitPoint.x(), hitPoint.y()) { > > > > > > // Except avoid early termination of rect-based hit test > > > // search in iframe case ... > > > if (!(request.isChildFrameHitTest() && > > > hitTestLocation.isRectBasedTest())) > > > fallback = true; > > > > > > // Mouse dragging outside the main document should also be > > > // delivered to the document > > > // TODO(dtapuska): Capture behavior inconsistent with iframes > crbug.com/XXXX > > > } else if ((request.active() || request.release()) && > > > !request.isChildFrameHitTest() { > > > fallback = true; > > > } > > > } > > > > > > > done. > > > > > If this formulation works, then you can also get rid of the hack Majid added > > in > > > > > > https://codereview.chromium.org/1210253003/diff/80001/Source/core/input/Event... > > > (but the argument that this mouse-drag specific fallback case belongs in > > > EventHandler, not DeprecatedPaintLayer is still true and maybe something you > > > want to try moving in a subsequent CL). > > > > Majid's CL adds a test case where wheel event is outside even the window > bounds, > > which is relying on the "... else if ((request.active() ... " condition to > > capture but not the condition "if (hitTestArea.contains(LayoutRect(hitRect))" > > which this CL is focusing on, so I can't really remove the active flag hack > for > > wheel event hit-test. > > I don't think part of the test is important, in fact I'd probably argue it's a > bug too (blink shouldn't be getting wheel events outside of the window entirely, > and if it does we probably shouldn't be scrolling). So I think you can just > update the test to not expect any events in the case where the co-ordinates are > entirely outside the wheel. Majid, do you agree? Actually, it is there for cases where the event is outside the root layer but inside window which can happen. See for example http://output.jsbin.com/kapogi There is an implicit assumption here that the hit-point is inside the window but I think that may not be valid for child frame hit testing which is a bug.
https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... Source/core/paint/DeprecatedPaintLayer.cpp:1518: } On 2015/08/19 21:02:30, majidvp wrote: > On 2015/08/19 19:23:19, Rick Byers wrote: > > On 2015/08/18 16:05:21, Yufeng Shen wrote: > > > On 2015/08/17 15:18:29, Rick Byers wrote: > > > > I think you could more clearly separate the confusing mix of hacky > > heuristics > > > > and reasonable behavior here if you reworked the condition as follows: > > > > > > > > if (!insideLayer && isRootLayer()) { > > > > > > > > // If we didn't hit any layers but are still inside the document > > > > // bounds, then we should fallback to hitting the document. > > > > if (hitTestArea.contains(hitPoint.x(), hitPoint.y()) { > > > > > > > > // Except avoid early termination of rect-based hit test > > > > // search in iframe case ... > > > > if (!(request.isChildFrameHitTest() && > > > > hitTestLocation.isRectBasedTest())) > > > > fallback = true; > > > > > > > > // Mouse dragging outside the main document should also be > > > > // delivered to the document > > > > // TODO(dtapuska): Capture behavior inconsistent with iframes > > crbug.com/XXXX > > > > } else if ((request.active() || request.release()) && > > > > !request.isChildFrameHitTest() { > > > > fallback = true; > > > > } > > > > } > > > > > > > > > > done. > > > > > > > If this formulation works, then you can also get rid of the hack Majid > added > > > in > > > > > > > > > > https://codereview.chromium.org/1210253003/diff/80001/Source/core/input/Event... > > > > (but the argument that this mouse-drag specific fallback case belongs in > > > > EventHandler, not DeprecatedPaintLayer is still true and maybe something > you > > > > want to try moving in a subsequent CL). > > > > > > Majid's CL adds a test case where wheel event is outside even the window > > bounds, > > > which is relying on the "... else if ((request.active() ... " condition to > > > capture but not the condition "if > (hitTestArea.contains(LayoutRect(hitRect))" > > > which this CL is focusing on, so I can't really remove the active flag hack > > for > > > wheel event hit-test. > > > > I don't think part of the test is important, in fact I'd probably argue it's a > > bug too (blink shouldn't be getting wheel events outside of the window > entirely, > > and if it does we probably shouldn't be scrolling). So I think you can just > > update the test to not expect any events in the case where the co-ordinates > are > > entirely outside the wheel. Majid, do you agree? > > Actually, it is there for cases where the event is outside the root layer but > inside window which can happen. See for example http://output.jsbin.com/kapogi > > There is an implicit assumption here that the hit-point is inside the window but > I think that may not be valid for child frame hit testing which is a bug. > I took a second look and I think Rick is correct and that part of the test (dispatch-mouse-events-to-window-always.html) which generates coordinate outside window is a bug and can be removed.
On 2015/08/20 16:29:35, majidvp wrote: > https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... > File Source/core/paint/DeprecatedPaintLayer.cpp (right): > > https://codereview.chromium.org/1289753006/diff/1/Source/core/paint/Deprecate... > Source/core/paint/DeprecatedPaintLayer.cpp:1518: } > On 2015/08/19 21:02:30, majidvp wrote: > > On 2015/08/19 19:23:19, Rick Byers wrote: > > > On 2015/08/18 16:05:21, Yufeng Shen wrote: > > > > On 2015/08/17 15:18:29, Rick Byers wrote: > > > > > I think you could more clearly separate the confusing mix of hacky > > > heuristics > > > > > and reasonable behavior here if you reworked the condition as follows: > > > > > > > > > > if (!insideLayer && isRootLayer()) { > > > > > > > > > > // If we didn't hit any layers but are still inside the document > > > > > // bounds, then we should fallback to hitting the document. > > > > > if (hitTestArea.contains(hitPoint.x(), hitPoint.y()) { > > > > > > > > > > // Except avoid early termination of rect-based hit test > > > > > // search in iframe case ... > > > > > if (!(request.isChildFrameHitTest() && > > > > > hitTestLocation.isRectBasedTest())) > > > > > fallback = true; > > > > > > > > > > // Mouse dragging outside the main document should also be > > > > > // delivered to the document > > > > > // TODO(dtapuska): Capture behavior inconsistent with iframes > > > crbug.com/XXXX > > > > > } else if ((request.active() || request.release()) && > > > > > !request.isChildFrameHitTest() { > > > > > fallback = true; > > > > > } > > > > > } > > > > > > > > > > > > > done. > > > > > > > > > If this formulation works, then you can also get rid of the hack Majid > > added > > > > in > > > > > > > > > > > > > > > https://codereview.chromium.org/1210253003/diff/80001/Source/core/input/Event... > > > > > (but the argument that this mouse-drag specific fallback case belongs in > > > > > EventHandler, not DeprecatedPaintLayer is still true and maybe something > > you > > > > > want to try moving in a subsequent CL). > > > > > > > > Majid's CL adds a test case where wheel event is outside even the window > > > bounds, > > > > which is relying on the "... else if ((request.active() ... " condition to > > > > capture but not the condition "if > > (hitTestArea.contains(LayoutRect(hitRect))" > > > > which this CL is focusing on, so I can't really remove the active flag > hack > > > for > > > > wheel event hit-test. > > > > > > I don't think part of the test is important, in fact I'd probably argue it's > a > > > bug too (blink shouldn't be getting wheel events outside of the window > > entirely, > > > and if it does we probably shouldn't be scrolling). So I think you can just > > > update the test to not expect any events in the case where the co-ordinates > > are > > > entirely outside the wheel. Majid, do you agree? > > > > Actually, it is there for cases where the event is outside the root layer but > > inside window which can happen. See for example http://output.jsbin.com/kapogi > > > > There is an implicit assumption here that the hit-point is inside the window > but > > I think that may not be valid for child frame hit testing which is a bug. > > > > I took a second look and I think Rick is correct and that part of the test > (dispatch-mouse-events-to-window-always.html) which generates coordinate outside > window is a bug and can be removed. "active" hack removed and Layout tests updated.
Great, thank you - love it! LGTM with nits https://codereview.chromium.org/1289753006/diff/40001/LayoutTests/fast/events... File LayoutTests/fast/events/resources/body-overflow-iframe.html (right): https://codereview.chromium.org/1289753006/diff/40001/LayoutTests/fast/events... LayoutTests/fast/events/resources/body-overflow-iframe.html:34: document.documentElement.scrollTop = "1000"; nit: please use document.scrollingElement in case I have to downgrade scrollTopLeftInterop again https://codereview.chromium.org/1289753006/diff/40001/Source/core/paint/Depre... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/40001/Source/core/paint/Depre... Source/core/paint/DeprecatedPaintLayer.cpp:1495: // TODO(majidvp): This should apply more consistently across different event types and we nit: please move this TODO to your second case - it doesn't apply to your first block. https://codereview.chromium.org/1289753006/diff/40001/Source/core/paint/Depre... Source/core/paint/DeprecatedPaintLayer.cpp:1507: // Mouse dragging outside the main document should also be nit: add a newline above here to make the separation of the two (very different) cases more clear.
https://codereview.chromium.org/1289753006/diff/40001/LayoutTests/fast/events... File LayoutTests/fast/events/resources/body-overflow-iframe.html (right): https://codereview.chromium.org/1289753006/diff/40001/LayoutTests/fast/events... LayoutTests/fast/events/resources/body-overflow-iframe.html:34: document.documentElement.scrollTop = "1000"; On 2015/08/20 19:28:22, Rick Byers wrote: > nit: please use document.scrollingElement in case I have to downgrade > scrollTopLeftInterop again Done. https://codereview.chromium.org/1289753006/diff/40001/Source/core/paint/Depre... File Source/core/paint/DeprecatedPaintLayer.cpp (right): https://codereview.chromium.org/1289753006/diff/40001/Source/core/paint/Depre... Source/core/paint/DeprecatedPaintLayer.cpp:1495: // TODO(majidvp): This should apply more consistently across different event types and we On 2015/08/20 19:28:22, Rick Byers wrote: > nit: please move this TODO to your second case - it doesn't apply to your first > block. Done. https://codereview.chromium.org/1289753006/diff/40001/Source/core/paint/Depre... Source/core/paint/DeprecatedPaintLayer.cpp:1507: // Mouse dragging outside the main document should also be On 2015/08/20 19:28:22, Rick Byers wrote: > nit: add a newline above here to make the separation of the two (very different) > cases more clear. Done.
The CQ bit was checked by miletus@chromium.org
The patchset sent to the CQ was uploaded after l-g-t-m from rbyers@chromium.org Link to the patchset: https://codereview.chromium.org/1289753006/#ps60001 (title: "address comments")
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1289753006/60001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1289753006/60001
The CQ bit was unchecked by commit-bot@chromium.org
Try jobs failed on following builders: win_chromium_rel_ng on tryserver.chromium.win (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.win/builders/win_chromium_rel_...)
The CQ bit was checked by miletus@chromium.org
The patchset sent to the CQ was uploaded after l-g-t-m from rbyers@chromium.org Link to the patchset: https://codereview.chromium.org/1289753006/#ps80001 (title: "fix layout test")
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1289753006/80001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1289753006/80001
Message was sent while issue was closed.
Committed patchset #5 (id:80001) as https://src.chromium.org/viewvc/blink?view=rev&revision=201188 |