Commit f27f8934 authored by Philip Rogers's avatar Philip Rogers Committed by Commit Bot

[PaintTouchActionRects] Paint window touch action rects

When the window has a blocking event handler, we need to ensure touch
action rects are painted. This patch paints the window touch action
rects using the LayoutView. In the PrePaint tree walk, blocking touch
event handlers on the window are considered when computing the
LayoutView's effective touch action.

With this change, ScrollingCoordinatorTest.IframeWindowTouchHandler
now passes with PaintTouchActionRects.

Bug: 851660
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel;luci.chromium.try:linux-blink-gen-property-trees
Change-Id: Ifbc9a9c60086ac8c92b6ff4829b3eda0513e3a36
Reviewed-on: https://chromium-review.googlesource.com/1104780
Commit-Queue: Philip Rogers <pdr@chromium.org>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568607}
parent 936b660c
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h" #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
...@@ -293,6 +294,12 @@ void EventHandlerRegistry::NotifyHasHandlersChanged( ...@@ -293,6 +294,12 @@ void EventHandlerRegistry::NotifyHasHandlersChanged(
if (auto* node = target->ToNode()) { if (auto* node = target->ToNode()) {
if (auto* layout_object = node->GetLayoutObject()) if (auto* layout_object = node->GetLayoutObject())
layout_object->MarkEffectiveWhitelistedTouchActionChanged(); layout_object->MarkEffectiveWhitelistedTouchActionChanged();
} else if (auto* dom_window = target->ToLocalDOMWindow()) {
// This event handler is on a window. Ensure the layout view is
// invalidated because the layout view tracks the window's blocking
// touch event rects.
if (auto* layout_view = dom_window->GetFrame()->ContentLayoutObject())
layout_view->MarkEffectiveWhitelistedTouchActionChanged();
} }
} }
} }
......
...@@ -955,33 +955,34 @@ TEST_P(ScrollingCoordinatorTest, touchActionOnScrollingElement) { ...@@ -955,33 +955,34 @@ TEST_P(ScrollingCoordinatorTest, touchActionOnScrollingElement) {
} }
TEST_P(ScrollingCoordinatorTest, IframeWindowTouchHandler) { TEST_P(ScrollingCoordinatorTest, IframeWindowTouchHandler) {
// TODO(pdr): Support window event handlers with PaintTouchActionRects.
if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled())
return;
LoadHTML( LoadHTML(
R"(<iframe style="width: 275px; height: 250px;"></iframe>)"); R"(<iframe style="width: 275px; height: 250px;"></iframe>)");
WebLocalFrameImpl* child_frame = WebLocalFrameImpl* child_frame =
ToWebLocalFrameImpl(GetWebView()->MainFrameImpl()->FirstChild()); ToWebLocalFrameImpl(GetWebView()->MainFrameImpl()->FirstChild());
FrameTestHelpers::LoadHTMLString(child_frame, FrameTestHelpers::LoadHTMLString(child_frame, R"HTML(
R"(<body> <p style="margin: 1000px"> Hello </p>
<p style="margin: 1000px"> Hello </p> <script>
<script> window.addEventListener('touchstart', (e) => {
window.addEventListener('touchstart', (e) => { e.preventDefault();
e.preventDefault(); }, {passive: false});
}, {passive: false}); </script>
</script> )HTML",
</body>)",
URLTestHelpers::ToKURL("about:blank")); URLTestHelpers::ToKURL("about:blank"));
ForceFullCompositingUpdate(); ForceFullCompositingUpdate();
PaintLayer* paint_layer_child_frame = PaintLayer* paint_layer_child_frame =
child_frame->GetFrame()->GetDocument()->GetLayoutView()->Layer(); child_frame->GetFrame()->GetDocument()->GetLayoutView()->Layer();
auto* child_mapping = paint_layer_child_frame->GetCompositedLayerMapping();
// With PaintTouchActionRects, touch action regions are stored on the layer
// that draws the background whereas without PaintTouchActionRects the main
// graphics layer is used.
auto* child_graphics_layer =
RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()
? child_mapping->ScrollingContentsLayer()
: child_mapping->MainGraphicsLayer();
cc::Region region_child_frame = cc::Region region_child_frame =
paint_layer_child_frame child_graphics_layer->CcLayer()
->EnclosingLayerForPaintInvalidationCrossingFrameBoundaries()
->GraphicsLayerBacking(&paint_layer_child_frame->GetLayoutObject())
->CcLayer()
->touch_action_region() ->touch_action_region()
.GetRegionForTouchAction(TouchAction::kTouchActionNone); .GetRegionForTouchAction(TouchAction::kTouchActionNone);
PaintLayer* paint_layer_main_frame = GetWebView() PaintLayer* paint_layer_main_frame = GetWebView()
...@@ -1001,8 +1002,102 @@ TEST_P(ScrollingCoordinatorTest, IframeWindowTouchHandler) { ...@@ -1001,8 +1002,102 @@ TEST_P(ScrollingCoordinatorTest, IframeWindowTouchHandler) {
EXPECT_FALSE(region_child_frame.bounds().IsEmpty()); EXPECT_FALSE(region_child_frame.bounds().IsEmpty());
// We only check for the content size for verification as the offset is 0x0 // We only check for the content size for verification as the offset is 0x0
// due to child frame having its own composited layer. // due to child frame having its own composited layer.
EXPECT_EQ(child_frame->GetFrameView()->ContentsSize(), if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
IntRect(region_child_frame.bounds()).Size()); // Because PaintTouchActionRects is painting the touch action rects on the
// scrolling contents layer, the size of the rect should be equal to the
// entire scrolling contents area.
EXPECT_EQ(child_graphics_layer->Size(),
IntSize(region_child_frame.bounds().size()));
} else {
EXPECT_EQ(child_frame->GetFrameView()->ContentsSize(),
IntRect(region_child_frame.bounds()).Size());
}
}
TEST_P(ScrollingCoordinatorTest, WindowTouchEventHandler) {
LoadHTML(R"HTML(
<style>
html { width: 200px; height: 200px; }
body { width: 100px; height: 100px; }
</style>
<script>
window.addEventListener('touchstart', function(event) {
event.preventDefault();
}, {passive: false} );
</script>
)HTML");
ForceFullCompositingUpdate();
auto* layout_view = GetFrame()->View()->GetLayoutView();
auto* mapping = layout_view->Layer()->GetCompositedLayerMapping();
// With PaintTouchActionRects, touch action regions are stored on the layer
// that draws the background whereas without PaintTouchActionRects the main
// graphics layer is used.
auto* graphics_layer = RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()
? mapping->ScrollingContentsLayer()
: mapping->MainGraphicsLayer();
// The touch action region should include the entire frame, even though the
// document is smaller than the frame.
cc::Region region =
graphics_layer->CcLayer()->touch_action_region().GetRegionForTouchAction(
TouchAction::kTouchActionNone);
EXPECT_EQ(region.bounds(), gfx::Rect(0, 0, 320, 240));
}
namespace {
class ScrollingCoordinatorMockEventListener final : public EventListener {
public:
ScrollingCoordinatorMockEventListener()
: EventListener(kCPPEventListenerType) {}
bool operator==(const EventListener& other) const final {
return this == &other;
}
void handleEvent(ExecutionContext*, Event*) final {}
};
} // namespace
TEST_P(ScrollingCoordinatorTest, WindowTouchEventHandlerInvalidation) {
LoadHTML("");
ForceFullCompositingUpdate();
auto* layout_view = GetFrame()->View()->GetLayoutView();
auto* mapping = layout_view->Layer()->GetCompositedLayerMapping();
// With PaintTouchActionRects, touch action regions are stored on the layer
// that draws the background whereas without PaintTouchActionRects the main
// graphics layer is used. Both approaches can implement correct behavior for
// window event handlers.
auto* graphics_layer = RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()
? mapping->ScrollingContentsLayer()
: mapping->MainGraphicsLayer();
auto* cc_layer = graphics_layer->CcLayer();
// Initially there are no touch action regions.
auto region = cc_layer->touch_action_region().GetRegionForTouchAction(
TouchAction::kTouchActionNone);
EXPECT_TRUE(region.IsEmpty());
// Adding a blocking window event handler should create a touch action region.
auto* listener = new ScrollingCoordinatorMockEventListener();
AddEventListenerOptions options;
options.setPassive(false);
AddEventListenerOptionsResolved resolved_options(options);
GetFrame()->DomWindow()->addEventListener(EventTypeNames::touchstart,
listener, resolved_options);
ForceFullCompositingUpdate();
region = cc_layer->touch_action_region().GetRegionForTouchAction(
TouchAction::kTouchActionNone);
EXPECT_FALSE(region.IsEmpty());
// Removing the window event handler also removes the blocking touch action
// region.
GetFrame()->DomWindow()->RemoveAllEventListeners();
ForceFullCompositingUpdate();
region = cc_layer->touch_action_region().GetRegionForTouchAction(
TouchAction::kTouchActionNone);
EXPECT_TRUE(region.IsEmpty());
} }
TEST_P(ScrollingCoordinatorTest, overflowScrolling) { TEST_P(ScrollingCoordinatorTest, overflowScrolling) {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "third_party/blink/renderer/core/dom/document_lifecycle.h" #include "third_party/blink/renderer/core/dom/document_lifecycle.h"
#include "third_party/blink/renderer/core/frame/event_handler_registry.h" #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/settings.h"
...@@ -144,16 +145,29 @@ bool PrePaintTreeWalk::NeedsEffectiveWhitelistedTouchActionUpdate( ...@@ -144,16 +145,29 @@ bool PrePaintTreeWalk::NeedsEffectiveWhitelistedTouchActionUpdate(
} }
namespace { namespace {
bool HasBlockingTouchEventHandler(const LayoutObject& object) { bool HasBlockingTouchEventHandler(const LocalFrame& frame,
auto* node = object.GetNode(); EventTarget& target) {
if (!node || !node->HasEventListeners()) if (!target.HasEventListeners())
return false; return false;
const auto& registry = object.GetFrame()->GetEventHandlerRegistry(); const auto& registry = frame.GetEventHandlerRegistry();
const auto* blocking = registry.EventHandlerTargets( const auto* blocking = registry.EventHandlerTargets(
EventHandlerRegistry::kTouchStartOrMoveEventBlocking); EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
const auto* blocking_low_latency = registry.EventHandlerTargets( const auto* blocking_low_latency = registry.EventHandlerTargets(
EventHandlerRegistry::kTouchStartOrMoveEventBlocking); EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
return blocking->Contains(node) || blocking_low_latency->Contains(node); return blocking->Contains(&target) || blocking_low_latency->Contains(&target);
}
bool HasBlockingTouchEventHandler(const LayoutObject& object) {
if (object.IsLayoutView()) {
auto* frame = object.GetFrame();
if (HasBlockingTouchEventHandler(*frame, *frame->DomWindow()))
return true;
}
auto* node = object.GetNode();
if (!node)
return false;
return HasBlockingTouchEventHandler(*object.GetFrame(), *node);
} }
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment