| Index: third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
|
| diff --git a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
|
| index 9fca4136977ee48f1cbc383fcf7596b21f0748de..cad37f0a4694fbd87d5b982c3e957ae387724262 100644
|
| --- a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
|
| +++ b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
|
| @@ -7,6 +7,7 @@
|
| #include "core/css/FontFaceSet.h"
|
| #include "core/dom/TaskRunnerHelper.h"
|
| #include "core/paint/PaintTiming.h"
|
| +#include "platform/Histogram.h"
|
| #include "platform/instrumentation/tracing/TraceEvent.h"
|
| #include "platform/loader/fetch/ResourceFetcher.h"
|
|
|
| @@ -18,9 +19,10 @@ namespace {
|
| // Meaningful Paint.
|
| const int kBlankCharactersThreshold = 200;
|
|
|
| -// FirstMeaningfulPaintDetector stops observing layouts and reports First
|
| -// Meaningful Paint when this duration passed from last network activity.
|
| -const double kSecondsWithoutNetworkActivityThreshold = 0.5;
|
| +// The page is n-quiet if there are no more than n active network requests for
|
| +// this duration of time.
|
| +const double kNetwork2QuietWindowSeconds = 3;
|
| +const double kNetwork0QuietWindowSeconds = 0.5;
|
|
|
| } // namespace
|
|
|
| @@ -52,7 +54,7 @@ void FirstMeaningfulPaintDetector::markNextPaintAsMeaningfulIfNeeded(
|
| int contentsHeightBeforeLayout,
|
| int contentsHeightAfterLayout,
|
| int visibleHeight) {
|
| - if (m_state == Reported)
|
| + if (m_networkState == Network0Quiet)
|
| return;
|
|
|
| unsigned delta = counter.count() - m_prevLayoutObjectCount;
|
| @@ -77,14 +79,14 @@ void FirstMeaningfulPaintDetector::markNextPaintAsMeaningfulIfNeeded(
|
| significance += m_accumulatedSignificanceWhileHavingBlankText;
|
| m_accumulatedSignificanceWhileHavingBlankText = 0;
|
| if (significance > m_maxSignificanceSoFar) {
|
| - m_state = NextPaintIsMeaningful;
|
| + m_nextPaintIsMeaningful = true;
|
| m_maxSignificanceSoFar = significance;
|
| }
|
| }
|
| }
|
|
|
| void FirstMeaningfulPaintDetector::notifyPaint() {
|
| - if (m_state != NextPaintIsMeaningful)
|
| + if (!m_nextPaintIsMeaningful)
|
| return;
|
|
|
| // Skip document background-only paints.
|
| @@ -92,7 +94,11 @@ void FirstMeaningfulPaintDetector::notifyPaint() {
|
| return;
|
|
|
| m_provisionalFirstMeaningfulPaint = monotonicallyIncreasingTime();
|
| - m_state = NextPaintIsNotMeaningful;
|
| + m_nextPaintIsMeaningful = false;
|
| + m_networkStateAtFirstMeaningfulPaint = m_networkState;
|
| +
|
| + if (m_networkState != NetworkActive)
|
| + return;
|
|
|
| TRACE_EVENT_MARK_WITH_TIMESTAMP1(
|
| "loading", "firstMeaningfulPaintCandidate",
|
| @@ -107,28 +113,74 @@ void FirstMeaningfulPaintDetector::notifyPaint() {
|
| m_paintTiming->markFirstMeaningfulPaintCandidate();
|
| }
|
|
|
| -void FirstMeaningfulPaintDetector::checkNetworkStable() {
|
| +bool FirstMeaningfulPaintDetector::isNetworkQuiet(int maxActiveConnections) {
|
| DCHECK(document());
|
| - if (m_state == Reported || document()->fetcher()->hasPendingRequest())
|
| - return;
|
| + if (!document()->hasFinishedParsing())
|
| + return false;
|
| + ResourceFetcher* fetcher = document()->fetcher();
|
| + return fetcher->blockingRequestCount() + fetcher->nonblockingRequestCount() <=
|
| + maxActiveConnections;
|
| +}
|
|
|
| - m_networkStableTimer.startOneShot(kSecondsWithoutNetworkActivityThreshold,
|
| - BLINK_FROM_HERE);
|
| +void FirstMeaningfulPaintDetector::checkNetworkStable() {
|
| + switch (m_networkState) {
|
| + case NetworkActive:
|
| + if (!isNetworkQuiet(2))
|
| + return;
|
| + m_networkStableTimer.startOneShot(kNetwork2QuietWindowSeconds,
|
| + BLINK_FROM_HERE);
|
| + break;
|
| +
|
| + case Network2Quiet:
|
| + if (!isNetworkQuiet(0))
|
| + return;
|
| + m_networkStableTimer.startOneShot(kNetwork0QuietWindowSeconds,
|
| + BLINK_FROM_HERE);
|
| + break;
|
| +
|
| + case Network0Quiet:
|
| + break;
|
| + }
|
| }
|
|
|
| void FirstMeaningfulPaintDetector::networkStableTimerFired(TimerBase*) {
|
| - if (m_state == Reported || !document() ||
|
| - document()->fetcher()->hasPendingRequest() ||
|
| - !m_paintTiming->firstContentfulPaint())
|
| + // This histogram is logged when the page reached network 0-quiet, so only
|
| + // possible values are NetworkActive and Network2Quiet.
|
| + DEFINE_STATIC_LOCAL(
|
| + EnumerationHistogram, networkStateAtFirstMeaningfulPaintHistogram,
|
| + ("PageLoad.Experimental.PaintTiming.NetworkStateAtFirstMeaningfulPaint",
|
| + Network0Quiet));
|
| +
|
| + if (!document())
|
| return;
|
|
|
| - if (m_provisionalFirstMeaningfulPaint) {
|
| - // Enforce FirstContentfulPaint <= FirstMeaningfulPaint.
|
| - double timestamp = std::max(m_provisionalFirstMeaningfulPaint,
|
| - m_paintTiming->firstContentfulPaint());
|
| - m_paintTiming->setFirstMeaningfulPaint(timestamp);
|
| + switch (m_networkState) {
|
| + case NetworkActive:
|
| + if (!isNetworkQuiet(2) || !m_paintTiming->firstContentfulPaint())
|
| + return;
|
| + m_networkState = Network2Quiet;
|
| + // Report FirstMeaningfulPaint when the page reached network 2-quiet.
|
| + if (m_provisionalFirstMeaningfulPaint) {
|
| + // Enforce FirstContentfulPaint <= FirstMeaningfulPaint.
|
| + double timestamp = std::max(m_provisionalFirstMeaningfulPaint,
|
| + m_paintTiming->firstContentfulPaint());
|
| + m_paintTiming->setFirstMeaningfulPaint(timestamp);
|
| + }
|
| + checkNetworkStable();
|
| + break;
|
| +
|
| + case Network2Quiet:
|
| + if (!isNetworkQuiet(0))
|
| + return;
|
| + m_networkState = Network0Quiet;
|
| + networkStateAtFirstMeaningfulPaintHistogram.count(
|
| + m_networkStateAtFirstMeaningfulPaint);
|
| + break;
|
| +
|
| + case Network0Quiet:
|
| + NOTREACHED();
|
| + break;
|
| }
|
| - m_state = Reported;
|
| }
|
|
|
| DEFINE_TRACE(FirstMeaningfulPaintDetector) {
|
|
|