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) { |