| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..199788a46792bbeaf5b32796d4523820fb034392
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
|
| @@ -0,0 +1,115 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "core/paint/FirstMeaningfulPaintDetector.h"
|
| +
|
| +#include "core/css/FontFaceSet.h"
|
| +#include "core/fetch/ResourceFetcher.h"
|
| +#include "core/paint/PaintTiming.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +// Web fonts that laid out more than this number of characters block First
|
| +// 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 = 2.0;
|
| +
|
| +} // namespace
|
| +
|
| +FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::from(Document& document)
|
| +{
|
| + return PaintTiming::from(document).firstMeaningfulPaintDetector();
|
| +}
|
| +
|
| +FirstMeaningfulPaintDetector::FirstMeaningfulPaintDetector(PaintTiming* paintTiming)
|
| + : m_paintTiming(paintTiming)
|
| + , m_networkStableTimer(this, &FirstMeaningfulPaintDetector::networkStableTimerFired)
|
| +{
|
| +}
|
| +
|
| +Document* FirstMeaningfulPaintDetector::document()
|
| +{
|
| + return m_paintTiming->document();
|
| +}
|
| +
|
| +// Computes "layout significance" (http://goo.gl/rytlPL) of a layout operation.
|
| +// Significance of a layout is the number of layout objects newly added to the
|
| +// layout tree, weighted by page height (before and after the layout).
|
| +// A paint after the most significance layout during page load is reported as
|
| +// First Meaningful Paint.
|
| +void FirstMeaningfulPaintDetector::markNextPaintAsMeaningfulIfNeeded(
|
| + const LayoutObjectCounter& counter, int contentsHeightBeforeLayout,
|
| + int contentsHeightAfterLayout, int visibleHeight)
|
| +{
|
| + if (m_state == Reported)
|
| + return;
|
| +
|
| + unsigned delta = counter.count() - m_prevLayoutObjectCount;
|
| + m_prevLayoutObjectCount = counter.count();
|
| +
|
| + if (visibleHeight == 0)
|
| + return;
|
| +
|
| + double ratioBefore = std::max(1.0, static_cast<double>(contentsHeightBeforeLayout) / visibleHeight);
|
| + double ratioAfter = std::max(1.0, static_cast<double>(contentsHeightAfterLayout) / visibleHeight);
|
| + double significance = delta / ((ratioBefore + ratioAfter) / 2);
|
| +
|
| + // If the page has many blank characters, the significance value is
|
| + // accumulated until the text become visible.
|
| + int approximateBlankCharacterCount = FontFaceSet::approximateBlankCharacterCount(*document());
|
| + if (approximateBlankCharacterCount > kBlankCharactersThreshold) {
|
| + m_accumulatedSignificanceWhileHavingBlankText += significance;
|
| + } else {
|
| + significance += m_accumulatedSignificanceWhileHavingBlankText;
|
| + m_accumulatedSignificanceWhileHavingBlankText = 0;
|
| + if (significance > m_maxSignificanceSoFar) {
|
| + m_state = NextPaintIsMeaningful;
|
| + m_maxSignificanceSoFar = significance;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void FirstMeaningfulPaintDetector::notifyPaint()
|
| +{
|
| + if (m_state != NextPaintIsMeaningful)
|
| + return;
|
| +
|
| + // Skip document background-only paints.
|
| + if (m_paintTiming->firstPaint() == 0.0)
|
| + return;
|
| +
|
| + m_provisionalFirstMeaningfulPaint = monotonicallyIncreasingTime();
|
| + m_state = NextPaintIsNotMeaningful;
|
| +}
|
| +
|
| +void FirstMeaningfulPaintDetector::checkNetworkStable()
|
| +{
|
| + DCHECK(document());
|
| + if (m_state == Reported || document()->fetcher()->hasPendingRequest())
|
| + return;
|
| +
|
| + m_networkStableTimer.startOneShot(kSecondsWithoutNetworkActivityThreshold, BLINK_FROM_HERE);
|
| +}
|
| +
|
| +void FirstMeaningfulPaintDetector::networkStableTimerFired(TimerBase*)
|
| +{
|
| + if (m_state == Reported || !document() || document()->fetcher()->hasPendingRequest())
|
| + return;
|
| +
|
| + if (m_provisionalFirstMeaningfulPaint)
|
| + m_paintTiming->setFirstMeaningfulPaint(m_provisionalFirstMeaningfulPaint);
|
| + m_state = Reported;
|
| +}
|
| +
|
| +DEFINE_TRACE(FirstMeaningfulPaintDetector)
|
| +{
|
| + visitor->trace(m_paintTiming);
|
| +}
|
| +
|
| +} // namespace blink
|
|
|