| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "core/paint/FirstMeaningfulPaintDetector.h" |
| 6 |
| 7 #include "core/css/FontFaceSet.h" |
| 8 #include "core/fetch/ResourceFetcher.h" |
| 9 #include "core/paint/PaintTiming.h" |
| 10 |
| 11 namespace blink { |
| 12 |
| 13 namespace { |
| 14 |
| 15 // Web fonts that laid out more than this number of characters block First |
| 16 // Meaningful Paint. |
| 17 const int kBlankCharactersThreshold = 200; |
| 18 |
| 19 // FirstMeaningfulPaintDetector stops observing layouts and reports First |
| 20 // Meaningful Paint when this duration passed from last network activity. |
| 21 const double kSecondsWithoutNetworkActivityThreshold = 2.0; |
| 22 |
| 23 } // namespace |
| 24 |
| 25 FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::from(Document& docum
ent) |
| 26 { |
| 27 return PaintTiming::from(document).firstMeaningfulPaintDetector(); |
| 28 } |
| 29 |
| 30 FirstMeaningfulPaintDetector::FirstMeaningfulPaintDetector(PaintTiming* paintTim
ing) |
| 31 : m_paintTiming(paintTiming) |
| 32 , m_networkStableTimer(this, &FirstMeaningfulPaintDetector::networkStableTim
erFired) |
| 33 { |
| 34 } |
| 35 |
| 36 Document* FirstMeaningfulPaintDetector::document() |
| 37 { |
| 38 return m_paintTiming->document(); |
| 39 } |
| 40 |
| 41 // Computes "layout significance" (http://goo.gl/rytlPL) of a layout operation. |
| 42 // Significance of a layout is the number of layout objects newly added to the |
| 43 // layout tree, weighted by page height (before and after the layout). |
| 44 // A paint after the most significance layout during page load is reported as |
| 45 // First Meaningful Paint. |
| 46 void FirstMeaningfulPaintDetector::markNextPaintAsMeaningfulIfNeeded( |
| 47 const LayoutObjectCounter& counter, int contentsHeightBeforeLayout, |
| 48 int contentsHeightAfterLayout, int visibleHeight) |
| 49 { |
| 50 if (m_state == Reported) |
| 51 return; |
| 52 |
| 53 unsigned delta = counter.count() - m_prevLayoutObjectCount; |
| 54 m_prevLayoutObjectCount = counter.count(); |
| 55 |
| 56 if (visibleHeight == 0) |
| 57 return; |
| 58 |
| 59 double ratioBefore = std::max(1.0, static_cast<double>(contentsHeightBeforeL
ayout) / visibleHeight); |
| 60 double ratioAfter = std::max(1.0, static_cast<double>(contentsHeightAfterLay
out) / visibleHeight); |
| 61 double significance = delta / ((ratioBefore + ratioAfter) / 2); |
| 62 |
| 63 // If the page has many blank characters, the significance value is |
| 64 // accumulated until the text become visible. |
| 65 int approximateBlankCharacterCount = FontFaceSet::approximateBlankCharacterC
ount(*document()); |
| 66 if (approximateBlankCharacterCount > kBlankCharactersThreshold) { |
| 67 m_accumulatedSignificanceWhileHavingBlankText += significance; |
| 68 } else { |
| 69 significance += m_accumulatedSignificanceWhileHavingBlankText; |
| 70 m_accumulatedSignificanceWhileHavingBlankText = 0; |
| 71 if (significance > m_maxSignificanceSoFar) { |
| 72 m_state = NextPaintIsMeaningful; |
| 73 m_maxSignificanceSoFar = significance; |
| 74 } |
| 75 } |
| 76 } |
| 77 |
| 78 void FirstMeaningfulPaintDetector::notifyPaint() |
| 79 { |
| 80 if (m_state != NextPaintIsMeaningful) |
| 81 return; |
| 82 |
| 83 // Skip document background-only paints. |
| 84 if (m_paintTiming->firstPaint() == 0.0) |
| 85 return; |
| 86 |
| 87 m_provisionalFirstMeaningfulPaint = monotonicallyIncreasingTime(); |
| 88 m_state = NextPaintIsNotMeaningful; |
| 89 } |
| 90 |
| 91 void FirstMeaningfulPaintDetector::checkNetworkStable() |
| 92 { |
| 93 DCHECK(document()); |
| 94 if (m_state == Reported || document()->fetcher()->hasPendingRequest()) |
| 95 return; |
| 96 |
| 97 m_networkStableTimer.startOneShot(kSecondsWithoutNetworkActivityThreshold, B
LINK_FROM_HERE); |
| 98 } |
| 99 |
| 100 void FirstMeaningfulPaintDetector::networkStableTimerFired(TimerBase*) |
| 101 { |
| 102 if (m_state == Reported || !document() || document()->fetcher()->hasPendingR
equest()) |
| 103 return; |
| 104 |
| 105 if (m_provisionalFirstMeaningfulPaint) |
| 106 m_paintTiming->setFirstMeaningfulPaint(m_provisionalFirstMeaningfulPaint
); |
| 107 m_state = Reported; |
| 108 } |
| 109 |
| 110 DEFINE_TRACE(FirstMeaningfulPaintDetector) |
| 111 { |
| 112 visitor->trace(m_paintTiming); |
| 113 } |
| 114 |
| 115 } // namespace blink |
| OLD | NEW |