Commit facf49bd authored by Chris Hamilton's avatar Chris Hamilton Committed by Commit Bot

[PM] Plumb FirstContentfulPaint to FrameNodes.

This will be used in upcoming page load prioritization logic.

BUG=1064763

Change-Id: I6290b4e500edc39759411f9a00f6f4255e1e0acd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2144312Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Reviewed-by: default avatarSigurður Ásgeirsson <siggi@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Cr-Commit-Position: refs/heads/master@{#758895}
parent d85ee3d9
......@@ -92,6 +92,10 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump,
// Ignored.
void OnHadFormInteractionChanged(
const performance_manager::FrameNode* frame_node) override {}
// Ignored.
void OnFirstContentfulPaint(
const performance_manager::FrameNode* frame_node,
base::TimeDelta time_since_navigation_start) override {}
// PageNodeObserver implementation:
void OnPageNodeAdded(const performance_manager::PageNode* page_node) override;
......
......@@ -87,15 +87,22 @@ void FrameNodeImpl::SetIsAdFrame() {
is_ad_frame_.SetAndMaybeNotify(this, true);
}
void FrameNodeImpl::SetHadFormInteraction() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
document_.had_form_interaction.SetAndMaybeNotify(this, true);
}
void FrameNodeImpl::OnNonPersistentNotificationCreated() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto* observer : GetObservers())
observer->OnNonPersistentNotificationCreated(this);
}
void FrameNodeImpl::SetHadFormInteraction() {
void FrameNodeImpl::OnFirstContentfulPaint(
base::TimeDelta time_since_navigation_start) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
document_.had_form_interaction.SetAndMaybeNotify(this, true);
for (auto* observer : GetObservers())
observer->OnFirstContentfulPaint(this, time_since_navigation_start);
}
const RenderFrameHostProxy& FrameNodeImpl::GetRenderFrameHostProxy() const {
......
......@@ -77,8 +77,10 @@ class FrameNodeImpl
void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override;
void SetOriginTrialFreezePolicy(mojom::InterventionPolicy policy) override;
void SetIsAdFrame() override;
void OnNonPersistentNotificationCreated() override;
void SetHadFormInteraction() override;
void OnNonPersistentNotificationCreated() override;
void OnFirstContentfulPaint(
base::TimeDelta time_since_navigation_start) override;
const RenderFrameHostProxy& GetRenderFrameHostProxy() const override;
// Partial FrameNodbase::TimeDelta time_since_navigatione implementation:
......
......@@ -137,10 +137,11 @@ class LenientMockObserver : public FrameNodeImpl::Observer {
MOCK_METHOD1(OnIsAdFrameChanged, void(const FrameNode*));
MOCK_METHOD1(OnFrameIsHoldingWebLockChanged, void(const FrameNode*));
MOCK_METHOD1(OnFrameIsHoldingIndexedDBLockChanged, void(const FrameNode*));
MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*));
MOCK_METHOD2(OnPriorityAndReasonChanged,
void(const FrameNode*, const PriorityAndReason& previous_value));
MOCK_METHOD1(OnHadFormInteractionChanged, void(const FrameNode*));
MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*));
MOCK_METHOD2(OnFirstContentfulPaint, void(const FrameNode*, base::TimeDelta));
void SetCreatedFrameNode(const FrameNode* frame_node) {
created_frame_node_ = frame_node;
......@@ -340,6 +341,21 @@ TEST_F(FrameNodeImplTest, FormInteractions) {
graph()->RemoveFrameNodeObserver(&obs);
}
TEST_F(FrameNodeImplTest, FirstContentfulPaint) {
auto process = CreateNode<ProcessNodeImpl>();
auto page = CreateNode<PageNodeImpl>();
auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
MockObserver obs;
graph()->AddFrameNodeObserver(&obs);
base::TimeDelta fcp = base::TimeDelta::FromMilliseconds(1364);
EXPECT_CALL(obs, OnFirstContentfulPaint(frame_node.get(), fcp));
frame_node->OnFirstContentfulPaint(fcp);
graph()->RemoveFrameNodeObserver(&obs);
}
TEST_F(FrameNodeImplTest, PublicInterface) {
auto process = CreateNode<ProcessNodeImpl>();
auto page = CreateNode<PageNodeImpl>();
......
......@@ -230,6 +230,15 @@ class FrameNodeObserver {
virtual void OnNonPersistentNotificationCreated(
const FrameNode* frame_node) = 0;
// Invoked when the frame has had a first contentful paint, as defined here:
// https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint
// This may not fire for all frames, depending on if the load is interrupted
// or if the content is even visible. It will fire at most once for a given
// frame. It will only fire for main-frame nodes.
virtual void OnFirstContentfulPaint(
const FrameNode* frame_node,
base::TimeDelta time_since_navigation_start) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(FrameNodeObserver);
};
......@@ -263,6 +272,9 @@ class FrameNode::ObserverDefaultImpl : public FrameNodeObserver {
void OnHadFormInteractionChanged(const FrameNode* frame_node) override {}
void OnNonPersistentNotificationCreated(
const FrameNode* frame_node) override {}
void OnFirstContentfulPaint(
const FrameNode* frame_node,
base::TimeDelta time_since_navigation_start) override {}
private:
DISALLOW_COPY_AND_ASSIGN(ObserverDefaultImpl);
......
......@@ -49,7 +49,18 @@ interface DocumentCoordinationUnit {
SetIsAdFrame();
// Event signals.
// Called when the associated frame has caused a non-persistent notification
// to be created.
OnNonPersistentNotificationCreated();
// Invoked when the frame associated with this document has had a first
// contentful paint, as defined here:
// https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint
// This may not fire for all frames, depending on if the load is interrupted
// or if the content is even visible. It will fire at most once for a given
// frame. It will only fire for main-frame nodes.
OnFirstContentfulPaint(mojo_base.mojom.TimeDelta time_since_navigation_start);
};
interface ProcessCoordinationUnit {
......
......@@ -21,6 +21,7 @@
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
......@@ -245,6 +246,12 @@ void PaintTiming::SetFirstContentfulPaintSwap(base::TimeTicks stamp) {
if (interactive_detector) {
interactive_detector->OnFirstContentfulPaint(first_contentful_paint_swap_);
}
auto* coordinator = GetSupplementable()->GetResourceCoordinator();
if (coordinator && GetFrame() && GetFrame()->IsMainFrame()) {
PerformanceTiming* timing = performance->timing();
base::TimeDelta fcp = stamp - timing->NavigationStartAsMonotonicTime();
coordinator->OnFirstContentfulPaint(fcp);
}
}
void PaintTiming::SetFirstImagePaintSwap(base::TimeTicks stamp) {
......
......@@ -72,4 +72,9 @@ void DocumentResourceCoordinator::SetHadFormInteraction() {
had_form_interaction_ = true;
}
void DocumentResourceCoordinator::OnFirstContentfulPaint(
base::TimeDelta time_since_navigation_start) {
service_->OnFirstContentfulPaint(time_since_navigation_start);
}
} // namespace blink
......@@ -35,6 +35,7 @@ class PLATFORM_EXPORT DocumentResourceCoordinator final {
void SetIsAdFrame();
void OnNonPersistentNotificationCreated();
void SetHadFormInteraction();
void OnFirstContentfulPaint(base::TimeDelta time_since_navigation_start);
private:
explicit DocumentResourceCoordinator(const BrowserInterfaceBrokerProxy&);
......
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