Commit 0a151519 authored by Steve Kobes's avatar Steve Kobes Committed by Commit Bot

Stop recording LCP after OOPIF input.

A subframe's PaintTimingDetector is supposed to stop recording after an
input, but we were only calling NotifyInputEvent on the same-site
codepath (WebViewImpl) and not the OOPIF codepath (WebFrameWidgetImpl).

This also ensures that we set first_input_or_scroll_notified_timestamp
in PageLoadMetrics timing updates after an OOPIF input.

Bug: 1115529
Change-Id: I9599d1cc7094551b899cfa19591eeaf5c85eb88b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2436770Reviewed-by: default avatarDave Tapuska <dtapuska@chromium.org>
Reviewed-by: default avatarNicolás Peña Moreno <npm@chromium.org>
Commit-Queue: Steve Kobes <skobes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813268}
parent b20e3037
<iframe id="f"></iframe>
<script>
f.src = origin.replace("example.com", "b.com") +
"/lcp_subframe_input_sub.html";
</script>
<div><img src="images/green-16x16.png"></div>
<div id="container"></div>
<script>
var last_url = null;
const test_step_1 = async () => {
return new Promise(resolve => {
new PerformanceObserver(list => {
resolve(last_url = list.getEntries()[0].url.match(/images\/(.*)/)[1]);
}).observe({type: 'largest-contentful-paint', buffered: true});
});
};
const test_step_2 = async () => {
let img = document.createElement("img");
let img_load = new Promise(resolve => {
new PerformanceObserver(list => {
if (list.getEntries().some(e => e.identifier == "blue"))
resolve();
}).observe({type: 'element'});
img.setAttribute("elementtiming", "blue");
});
container.appendChild(img);
img.src = "images/blue96x96.png";
await img_load;
await new Promise(resolve => { requestAnimationFrame(resolve); });
return last_url;
};
</script>
...@@ -130,3 +130,17 @@ IN_PROC_BROWSER_TEST_F(MetricIntegrationTest, LargestContentfulPaint) { ...@@ -130,3 +130,17 @@ IN_PROC_BROWSER_TEST_F(MetricIntegrationTest, LargestContentfulPaint) {
"PageLoad.PaintTiming.NavigationToLargestContentfulPaint.MainFrame", "PageLoad.PaintTiming.NavigationToLargestContentfulPaint.MainFrame",
lcp_timestamps[2].value()); lcp_timestamps[2].value());
} }
IN_PROC_BROWSER_TEST_F(MetricIntegrationTest,
LargestContentfulPaint_SubframeInput) {
Start();
Load("/lcp_subframe_input.html");
auto* sub = ChildFrameAt(web_contents()->GetMainFrame(), 0);
EXPECT_EQ(EvalJs(sub, "test_step_1()").value.GetString(), "green-16x16.png");
content::SimulateMouseClickAt(web_contents(), 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(100, 100));
EXPECT_EQ(EvalJs(sub, "test_step_2()").value.GetString(), "green-16x16.png");
}
...@@ -112,6 +112,8 @@ void MetricIntegrationTest::SetUpCommandLine(CommandLine* command_line) { ...@@ -112,6 +112,8 @@ void MetricIntegrationTest::SetUpCommandLine(CommandLine* command_line) {
// Set a default window size for consistency. // Set a default window size for consistency.
command_line->AppendSwitchASCII(switches::kWindowSize, "800,600"); command_line->AppendSwitchASCII(switches::kWindowSize, "800,600");
command_line->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures); command_line->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
content::IsolateAllSitesForTesting(command_line);
} }
std::unique_ptr<HttpResponse> MetricIntegrationTest::HandleRequest( std::unique_ptr<HttpResponse> MetricIntegrationTest::HandleRequest(
......
...@@ -2323,6 +2323,9 @@ WebInputEventResult WebViewImpl::HandleInputEvent( ...@@ -2323,6 +2323,9 @@ WebInputEventResult WebViewImpl::HandleInputEvent(
return WebInputEventResult::kNotHandled; return WebInputEventResult::kNotHandled;
DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType())); DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType()));
WebFrameWidgetBase* widget = MainFrameImpl()->FrameWidgetImpl();
DCHECK(widget);
GetPage()->GetVisualViewport().StartTrackingPinchStats(); GetPage()->GetVisualViewport().StartTrackingPinchStats();
TRACE_EVENT1("input,rail", "WebViewImpl::handleInputEvent", "type", TRACE_EVENT1("input,rail", "WebViewImpl::handleInputEvent", "type",
...@@ -2330,7 +2333,7 @@ WebInputEventResult WebViewImpl::HandleInputEvent( ...@@ -2330,7 +2333,7 @@ WebInputEventResult WebViewImpl::HandleInputEvent(
// If a drag-and-drop operation is in progress, ignore input events except // If a drag-and-drop operation is in progress, ignore input events except
// PointerCancel. // PointerCancel.
if (MainFrameImpl()->FrameWidgetImpl()->DoingDragAndDrop() && if (widget->DoingDragAndDrop() &&
input_event.GetType() != WebInputEvent::Type::kPointerCancel) input_event.GetType() != WebInputEvent::Type::kPointerCancel)
return WebInputEventResult::kHandledSuppressed; return WebInputEventResult::kHandledSuppressed;
...@@ -2350,14 +2353,12 @@ WebInputEventResult WebViewImpl::HandleInputEvent( ...@@ -2350,14 +2353,12 @@ WebInputEventResult WebViewImpl::HandleInputEvent(
UIEventWithKeyState::ClearNewTabModifierSetFromIsolatedWorld(); UIEventWithKeyState::ClearNewTabModifierSetFromIsolatedWorld();
bool is_pointer_locked = false; bool is_pointer_locked = false;
if (WebFrameWidgetBase* widget = MainFrameImpl()->FrameWidgetImpl()) { if (WebWidgetClient* client = widget->Client())
if (WebWidgetClient* client = widget->Client()) is_pointer_locked = client->IsPointerLocked();
is_pointer_locked = client->IsPointerLocked();
}
if (is_pointer_locked && if (is_pointer_locked &&
WebInputEvent::IsMouseEventType(input_event.GetType())) { WebInputEvent::IsMouseEventType(input_event.GetType())) {
MainFrameImpl()->FrameWidgetImpl()->PointerLockMouseEvent(coalesced_event); widget->PointerLockMouseEvent(coalesced_event);
return WebInputEventResult::kHandledSystem; return WebInputEventResult::kHandledSystem;
} }
...@@ -2377,16 +2378,12 @@ WebInputEventResult WebViewImpl::HandleInputEvent( ...@@ -2377,16 +2378,12 @@ WebInputEventResult WebViewImpl::HandleInputEvent(
} }
} }
widget->NotifyInputObservers(coalesced_event);
// Notify the focus frame of the input. Note that the other frames are not // Notify the focus frame of the input. Note that the other frames are not
// notified as input is only handled by the focused frame. // notified as input is only handled by the focused frame.
Frame* frame = FocusedCoreFrame(); Frame* frame = FocusedCoreFrame();
if (auto* local_frame = DynamicTo<LocalFrame>(frame)) { if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
if (local_frame->View() && local_frame->View()
->GetPaintTimingDetector()
.NeedToNotifyInputOrScroll()) {
local_frame->View()->GetPaintTimingDetector().NotifyInputEvent(
input_event.GetType());
}
if (auto* content_capture_manager = if (auto* content_capture_manager =
local_frame->LocalFrameRoot().GetContentCaptureManager()) { local_frame->LocalFrameRoot().GetContentCaptureManager()) {
content_capture_manager->NotifyInputEvent(input_event.GetType(), content_capture_manager->NotifyInputEvent(input_event.GetType(),
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/pointer_lock_controller.h" #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h" #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h" #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
#include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h" #include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
...@@ -2299,4 +2300,21 @@ void WebFrameWidgetBase::WasShown(bool was_evicted) { ...@@ -2299,4 +2300,21 @@ void WebFrameWidgetBase::WasShown(bool was_evicted) {
} }
} }
void WebFrameWidgetBase::NotifyInputObservers(
const WebCoalescedInputEvent& coalesced_event) {
LocalFrame* frame = FocusedLocalFrameInWidget();
if (!frame)
return;
LocalFrameView* frame_view = frame->View();
if (!frame_view)
return;
const WebInputEvent& input_event = coalesced_event.Event();
auto& paint_timing_detector = frame_view->GetPaintTimingDetector();
if (paint_timing_detector.NeedToNotifyInputOrScroll())
paint_timing_detector.NotifyInputEvent(input_event.GetType());
}
} // namespace blink } // namespace blink
...@@ -607,6 +607,11 @@ class CORE_EXPORT WebFrameWidgetBase ...@@ -607,6 +607,11 @@ class CORE_EXPORT WebFrameWidgetBase
void NotifyPageScaleFactorChanged(float page_scale_factor, void NotifyPageScaleFactorChanged(float page_scale_factor,
bool is_pinch_gesture_active); bool is_pinch_gesture_active);
// Helper for notifying frame-level objects that care about input events.
// TODO: With some effort, this could be folded into a common implementation
// of WebViewImpl::HandleInputEvent and WebFrameWidgetImpl::HandleInputEvent.
void NotifyInputObservers(const WebCoalescedInputEvent& coalesced_event);
// A copy of the web drop data object we received from the browser. // A copy of the web drop data object we received from the browser.
Member<DataObject> current_drag_data_; Member<DataObject> current_drag_data_;
......
...@@ -490,6 +490,8 @@ WebInputEventResult WebFrameWidgetImpl::HandleInputEvent( ...@@ -490,6 +490,8 @@ WebInputEventResult WebFrameWidgetImpl::HandleInputEvent(
return WebInputEventResult::kHandledSystem; return WebInputEventResult::kHandledSystem;
} }
NotifyInputObservers(coalesced_event);
if (mouse_capture_element_ && if (mouse_capture_element_ &&
WebInputEvent::IsMouseEventType(input_event.GetType())) { WebInputEvent::IsMouseEventType(input_event.GetType())) {
TRACE_EVENT1("input", "captured mouse event", "type", TRACE_EVENT1("input", "captured mouse event", "type",
......
...@@ -67,6 +67,11 @@ class WebMouseEvent; ...@@ -67,6 +67,11 @@ class WebMouseEvent;
class WebMouseWheelEvent; class WebMouseWheelEvent;
class WebFrameWidgetImpl; class WebFrameWidgetImpl;
// Implements WebFrameWidget for a child local root frame (OOPIF). This object
// is created in the child renderer and attached to the OOPIF's WebLocalFrame.
//
// For the main frame's WebFrameWidget implementation, see WebViewFrameWidget.
//
class WebFrameWidgetImpl final : public WebFrameWidgetBase, class WebFrameWidgetImpl final : public WebFrameWidgetBase,
public PageWidgetEventHandler { public PageWidgetEventHandler {
public: public:
......
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