Commit fbbdff52 authored by Liquan(Max) Gu's avatar Liquan(Max) Gu Committed by Commit Bot

[LCP] Text: wrap largest text paint in a class

Currently, we are using flags (is_reporting_lcp_) to stop the
largest-text-paint pipeline in TextPaintTimingDetector. However,
the flag is hard to maintain and is error-prone. To fix this issue,
we introduce a wrapper for the largest-text-paint part of code.
Once we stop largest-text-paint, we set the wrapper instance to null.
This way, any data structure and functions of this pipeline would no
longer be accessible.

In this patch, we also remove the timer. The removal is included in
this patch because it's part of the largest-text-paint pipeline.
Although the removal is a relatively separate part, we suggest
including it here because making it two steps would complicate the
middle state.

The removal of timer has several benefits:
1) can avoid the complicated control logic of timer.
2) can make the metric result more precise, because we move the result
update from the 1s-timer callback to the swap-time assignment callback.

Bug:977181,977926,977952

Change-Id: I01821517ee9a01c70ad65dd901b0f3d687bbb1de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1672113
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarLiquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarNicolás Peña Moreno <npm@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#671941}
parent 0aa7df50
...@@ -76,9 +76,6 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest { ...@@ -76,9 +76,6 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
.GetTextPaintTimingDetector(); .GetTextPaintTimingDetector();
text_detector->ReportSwapTime(WebWidgetClient::SwapResult::kDidSwap, text_detector->ReportSwapTime(WebWidgetClient::SwapResult::kDidSwap,
simulated_clock_.NowTicks()); simulated_clock_.NowTicks());
// TexPaintTimingDetector does not update the candidate on the swap
// callback, so manually call it.
text_detector->UpdateCandidate();
} }
private: private:
......
...@@ -54,7 +54,7 @@ bool IsBackgroundImageContentful(const LayoutObject& object, ...@@ -54,7 +54,7 @@ bool IsBackgroundImageContentful(const LayoutObject& object,
PaintTimingDetector::PaintTimingDetector(LocalFrameView* frame_view) PaintTimingDetector::PaintTimingDetector(LocalFrameView* frame_view)
: frame_view_(frame_view), : frame_view_(frame_view),
text_paint_timing_detector_( text_paint_timing_detector_(
MakeGarbageCollected<TextPaintTimingDetector>(frame_view)), MakeGarbageCollected<TextPaintTimingDetector>(frame_view, this)),
image_paint_timing_detector_( image_paint_timing_detector_(
MakeGarbageCollected<ImagePaintTimingDetector>(frame_view)) {} MakeGarbageCollected<ImagePaintTimingDetector>(frame_view)) {}
......
...@@ -42,7 +42,7 @@ FloatRect TextElementTiming::ComputeIntersectionRect( ...@@ -42,7 +42,7 @@ FloatRect TextElementTiming::ComputeIntersectionRect(
Node* node, Node* node,
const IntRect& aggregated_visual_rect, const IntRect& aggregated_visual_rect,
const PropertyTreeState& property_tree_state, const PropertyTreeState& property_tree_state,
LocalFrameView* frame_view) { const LocalFrameView* frame_view) {
if (!NeededForElementTiming(node)) if (!NeededForElementTiming(node))
return FloatRect(); return FloatRect();
......
...@@ -44,7 +44,7 @@ class CORE_EXPORT TextElementTiming final ...@@ -44,7 +44,7 @@ class CORE_EXPORT TextElementTiming final
Node*, Node*,
const IntRect& aggregated_visual_rect, const IntRect& aggregated_visual_rect,
const PropertyTreeState&, const PropertyTreeState&,
LocalFrameView*); const LocalFrameView*);
// Called when the swap promise queued by TextPaintTimingDetector has been // Called when the swap promise queued by TextPaintTimingDetector has been
// resolved. Dispatches PerformanceElementTiming entries to WindowPerformance. // resolved. Dispatches PerformanceElementTiming entries to WindowPerformance.
......
...@@ -27,8 +27,6 @@ namespace blink { ...@@ -27,8 +27,6 @@ namespace blink {
namespace { namespace {
// Calculate metrics candidate every 1 second after the first text pre-paint.
constexpr base::TimeDelta kTimerDelay = base::TimeDelta::FromSeconds(1);
constexpr size_t kTextNodeNumberLimit = 5000; constexpr size_t kTextNodeNumberLimit = 5000;
bool LargeTextFirst(const base::WeakPtr<TextRecord>& a, bool LargeTextFirst(const base::WeakPtr<TextRecord>& a,
...@@ -44,14 +42,13 @@ bool LargeTextFirst(const base::WeakPtr<TextRecord>& a, ...@@ -44,14 +42,13 @@ bool LargeTextFirst(const base::WeakPtr<TextRecord>& a,
} // namespace } // namespace
TextPaintTimingDetector::TextPaintTimingDetector(LocalFrameView* frame_view) TextPaintTimingDetector::TextPaintTimingDetector(
: records_manager_(), LocalFrameView* frame_view,
timer_(frame_view->GetFrame().GetTaskRunner(TaskType::kInternalDefault), PaintTimingDetector* paint_timing_detector)
this, : records_manager_(frame_view, paint_timing_detector),
&TextPaintTimingDetector::TimerFired),
frame_view_(frame_view) {} frame_view_(frame_view) {}
void TextPaintTimingDetector::PopulateTraceValue( void LargestTextPaintManager::PopulateTraceValue(
TracedValue& value, TracedValue& value,
const TextRecord& first_text_paint) { const TextRecord& first_text_paint) {
// TODO(crbug.com/976893): Remove DOMNodeId. // TODO(crbug.com/976893): Remove DOMNodeId.
...@@ -63,7 +60,7 @@ void TextPaintTimingDetector::PopulateTraceValue( ...@@ -63,7 +60,7 @@ void TextPaintTimingDetector::PopulateTraceValue(
!frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()); !frame_view_->GetFrame().LocalFrameRoot().IsMainFrame());
} }
void TextPaintTimingDetector::ReportCandidateToTrace( void LargestTextPaintManager::ReportCandidateToTrace(
const TextRecord& largest_text_record) { const TextRecord& largest_text_record) {
auto value = std::make_unique<TracedValue>(); auto value = std::make_unique<TracedValue>();
PopulateTraceValue(*value, largest_text_record); PopulateTraceValue(*value, largest_text_record);
...@@ -75,7 +72,7 @@ void TextPaintTimingDetector::ReportCandidateToTrace( ...@@ -75,7 +72,7 @@ void TextPaintTimingDetector::ReportCandidateToTrace(
ToTraceValue(&frame_view_->GetFrame())); ToTraceValue(&frame_view_->GetFrame()));
} }
void TextPaintTimingDetector::ReportNoCandidateToTrace() { void LargestTextPaintManager::ReportNoCandidateToTrace() {
auto value = std::make_unique<TracedValue>(); auto value = std::make_unique<TracedValue>();
value->SetInteger("candidateIndex", ++count_candidates_); value->SetInteger("candidateIndex", ++count_candidates_);
value->SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame()); value->SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame());
...@@ -86,37 +83,26 @@ void TextPaintTimingDetector::ReportNoCandidateToTrace() { ...@@ -86,37 +83,26 @@ void TextPaintTimingDetector::ReportNoCandidateToTrace() {
ToTraceValue(&frame_view_->GetFrame())); ToTraceValue(&frame_view_->GetFrame()));
} }
// The timer has guaranteed that |this| exists when this function is invoked. void LargestTextPaintManager::UpdateCandidate() {
void TextPaintTimingDetector::TimerFired(TimerBase* time) { base::WeakPtr<TextRecord> largest_text_record = FindLargestPaintCandidate();
// Wrap |UpdateCandidate| method in TimerFired so that we can drop |time| for
// |UpdateCandidate| in testing.
UpdateCandidate();
}
void TextPaintTimingDetector::UpdateCandidate() {
if (!is_recording_)
return;
if (!is_recording_ltp_)
return;
DCHECK(RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled());
base::WeakPtr<TextRecord> largest_text_record =
records_manager_.FindLargestPaintCandidate();
const base::TimeTicks time = const base::TimeTicks time =
largest_text_record ? largest_text_record->paint_time : base::TimeTicks(); largest_text_record ? largest_text_record->paint_time : base::TimeTicks();
const uint64_t size = const uint64_t size =
largest_text_record ? largest_text_record->first_size : 0; largest_text_record ? largest_text_record->first_size : 0;
PaintTimingDetector& detector = frame_view_->GetPaintTimingDetector(); DCHECK(paint_timing_detector_);
bool changed = detector.NotifyIfChangedLargestTextPaint(time, size); bool changed =
paint_timing_detector_->NotifyIfChangedLargestTextPaint(time, size);
if (!changed) if (!changed)
return; return;
if (largest_text_record && !largest_text_record->paint_time.is_null()) { if (largest_text_record && !largest_text_record->paint_time.is_null()) {
if (auto* lcp_calculator = detector.GetLargestContentfulPaintCalculator()) if (auto* lcp_calculator =
paint_timing_detector_->GetLargestContentfulPaintCalculator())
lcp_calculator->OnLargestTextUpdated(largest_text_record); lcp_calculator->OnLargestTextUpdated(largest_text_record);
ReportCandidateToTrace(*largest_text_record); ReportCandidateToTrace(*largest_text_record);
} else { } else {
if (auto* lcp_calculator = detector.GetLargestContentfulPaintCalculator()) if (auto* lcp_calculator =
paint_timing_detector_->GetLargestContentfulPaintCalculator())
lcp_calculator->OnLargestTextUpdated(nullptr); lcp_calculator->OnLargestTextUpdated(nullptr);
ReportNoCandidateToTrace(); ReportNoCandidateToTrace();
} }
...@@ -125,12 +111,10 @@ void TextPaintTimingDetector::UpdateCandidate() { ...@@ -125,12 +111,10 @@ void TextPaintTimingDetector::UpdateCandidate() {
void TextPaintTimingDetector::OnPaintFinished() { void TextPaintTimingDetector::OnPaintFinished() {
if (need_update_timing_at_frame_end_) { if (need_update_timing_at_frame_end_) {
need_update_timing_at_frame_end_ = false; need_update_timing_at_frame_end_ = false;
UpdateCandidate(); if (records_manager_.GetLargestTextPaintManager())
records_manager_.GetLargestTextPaintManager()->UpdateCandidate();
} }
if (records_manager_.NeedMeausuringPaintTime()) { if (records_manager_.NeedMeausuringPaintTime()) {
// Start repeating timer only once at the first text paint.
if (!timer_.IsActive() && is_recording_ltp_)
timer_.StartRepeating(kTimerDelay, FROM_HERE);
if (!awaiting_swap_promise_) { if (!awaiting_swap_promise_) {
// |WrapCrossThreadWeakPersistent| guarantees that when |this| is killed, // |WrapCrossThreadWeakPersistent| guarantees that when |this| is killed,
// the callback function will not be invoked. // the callback function will not be invoked.
...@@ -180,6 +164,8 @@ void TextPaintTimingDetector::ReportSwapTime(WebWidgetClient::SwapResult result, ...@@ -180,6 +164,8 @@ void TextPaintTimingDetector::ReportSwapTime(WebWidgetClient::SwapResult result,
} }
} }
records_manager_.AssignPaintTimeToQueuedNodes(timestamp); records_manager_.AssignPaintTimeToQueuedNodes(timestamp);
if (records_manager_.GetLargestTextPaintManager())
records_manager_.GetLargestTextPaintManager()->UpdateCandidate();
awaiting_swap_promise_ = false; awaiting_swap_promise_ = false;
} }
...@@ -195,7 +181,8 @@ bool TextPaintTimingDetector::ShouldWalkObject( ...@@ -195,7 +181,8 @@ bool TextPaintTimingDetector::ShouldWalkObject(
// If we have finished recording Largest Text Paint and the element is a // If we have finished recording Largest Text Paint and the element is a
// shadow element or has no elementtiming attribute, then we should not record // shadow element or has no elementtiming attribute, then we should not record
// its text. // its text.
if (!is_recording_ltp_ && !TextElementTiming::NeededForElementTiming(node)) if (!records_manager_.IsRecordingLargestTextPaint() &&
!TextElementTiming::NeededForElementTiming(node))
return false; return false;
DOMNodeId node_id = DOMNodeIds::ExistingIdForNode(node); DOMNodeId node_id = DOMNodeIds::ExistingIdForNode(node);
...@@ -246,20 +233,13 @@ void TextPaintTimingDetector::RecordAggregatedText( ...@@ -246,20 +233,13 @@ void TextPaintTimingDetector::RecordAggregatedText(
} }
} }
base::WeakPtr<TextRecord> TextPaintTimingDetector::FindLargestPaintCandidate() {
return records_manager_.FindLargestPaintCandidate();
}
void TextPaintTimingDetector::StopRecordEntries() { void TextPaintTimingDetector::StopRecordEntries() {
timer_.Stop();
is_recording_ = false; is_recording_ = false;
records_manager_.CleanUp(); records_manager_.CleanUp();
} }
void TextPaintTimingDetector::StopRecordingLargestTextPaint() { void TextPaintTimingDetector::StopRecordingLargestTextPaint() {
timer_.Stop(); records_manager_.CleanUpLargestTextPaint();
is_recording_ltp_ = false;
records_manager_.CleanUpLargestContentfulPaint();
} }
void TextPaintTimingDetector::Trace(blink::Visitor* visitor) { void TextPaintTimingDetector::Trace(blink::Visitor* visitor) {
...@@ -267,26 +247,36 @@ void TextPaintTimingDetector::Trace(blink::Visitor* visitor) { ...@@ -267,26 +247,36 @@ void TextPaintTimingDetector::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_view_); visitor->Trace(frame_view_);
} }
TextRecordsManager::TextRecordsManager() : size_ordered_set_(&LargeTextFirst) {} LargestTextPaintManager::LargestTextPaintManager(
LocalFrameView* frame_view,
PaintTimingDetector* paint_timing_detector)
: size_ordered_set_(&LargeTextFirst),
frame_view_(frame_view),
paint_timing_detector_(paint_timing_detector) {}
void LargestTextPaintManager::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_view_);
visitor->Trace(paint_timing_detector_);
}
void TextRecordsManager::RemoveVisibleRecord(const LayoutObject& object) { void TextRecordsManager::RemoveVisibleRecord(const LayoutObject& object) {
DCHECK(visible_node_map_.Contains(&object)); DCHECK(visible_node_map_.Contains(&object));
size_ordered_set_.erase(visible_node_map_.at(&object)->AsWeakPtr()); if (ltp_manager_) {
ltp_manager_->RemoveVisibleRecord(
visible_node_map_.at(&object)->AsWeakPtr());
}
visible_node_map_.erase(&object); visible_node_map_.erase(&object);
// We don't need to remove elements in |texts_queued_for_paint_time_| and // We don't need to remove elements in |texts_queued_for_paint_time_| and
// |cached_largest_paint_candidate_| as they are weak ptr. // |cached_largest_paint_candidate_| as they are weak ptr.
is_result_invalidated_ = true;
} }
void TextRecordsManager::CleanUpLargestContentfulPaint() { void TextRecordsManager::CleanUpLargestTextPaint() {
size_ordered_set_.clear(); ltp_manager_.reset();
is_result_invalidated_ = true;
} }
void TextRecordsManager::RemoveInvisibleRecord(const LayoutObject& object) { void TextRecordsManager::RemoveInvisibleRecord(const LayoutObject& object) {
DCHECK(invisible_node_ids_.Contains(&object)); DCHECK(invisible_node_ids_.Contains(&object));
invisible_node_ids_.erase(&object); invisible_node_ids_.erase(&object);
is_result_invalidated_ = true;
} }
void TextRecordsManager::AssignPaintTimeToQueuedNodes( void TextRecordsManager::AssignPaintTimeToQueuedNodes(
...@@ -310,7 +300,8 @@ void TextRecordsManager::AssignPaintTimeToQueuedNodes( ...@@ -310,7 +300,8 @@ void TextRecordsManager::AssignPaintTimeToQueuedNodes(
if (text_element_timing_) if (text_element_timing_)
text_element_timing_->OnTextNodesPainted(texts_queued_for_paint_time_); text_element_timing_->OnTextNodesPainted(texts_queued_for_paint_time_);
texts_queued_for_paint_time_.clear(); texts_queued_for_paint_time_.clear();
is_result_invalidated_ = true; if (ltp_manager_)
ltp_manager_->SetCachedResultInvalidated(true);
} }
void TextRecordsManager::RecordVisibleObject( void TextRecordsManager::RecordVisibleObject(
...@@ -323,11 +314,12 @@ void TextRecordsManager::RecordVisibleObject( ...@@ -323,11 +314,12 @@ void TextRecordsManager::RecordVisibleObject(
std::unique_ptr<TextRecord> record = std::unique_ptr<TextRecord> record =
std::make_unique<TextRecord>(node_id, visual_size, element_timing_rect); std::make_unique<TextRecord>(node_id, visual_size, element_timing_rect);
if (is_recording_ltp_) base::WeakPtr<TextRecord> record_weak_ptr = record->AsWeakPtr();
size_ordered_set_.emplace(record->AsWeakPtr()); if (ltp_manager_)
QueueToMeasurePaintTime(record->AsWeakPtr()); ltp_manager_->InsertRecord(record_weak_ptr);
QueueToMeasurePaintTime(record_weak_ptr);
visible_node_map_.insert(&object, std::move(record)); visible_node_map_.insert(&object, std::move(record));
is_result_invalidated_ = true;
} }
bool TextRecordsManager::HasTooManyNodes() const { bool TextRecordsManager::HasTooManyNodes() const {
...@@ -335,8 +327,7 @@ bool TextRecordsManager::HasTooManyNodes() const { ...@@ -335,8 +327,7 @@ bool TextRecordsManager::HasTooManyNodes() const {
kTextNodeNumberLimit; kTextNodeNumberLimit;
} }
base::WeakPtr<TextRecord> TextRecordsManager::FindLargestPaintCandidate() { base::WeakPtr<TextRecord> LargestTextPaintManager::FindLargestPaintCandidate() {
DCHECK_EQ(visible_node_map_.size(), size_ordered_set_.size());
if (!is_result_invalidated_ && cached_largest_paint_candidate_) if (!is_result_invalidated_ && cached_largest_paint_candidate_)
return cached_largest_paint_candidate_; return cached_largest_paint_candidate_;
base::WeakPtr<TextRecord> new_largest_paint_candidate = nullptr; base::WeakPtr<TextRecord> new_largest_paint_candidate = nullptr;
...@@ -352,15 +343,23 @@ base::WeakPtr<TextRecord> TextRecordsManager::FindLargestPaintCandidate() { ...@@ -352,15 +343,23 @@ base::WeakPtr<TextRecord> TextRecordsManager::FindLargestPaintCandidate() {
return new_largest_paint_candidate; return new_largest_paint_candidate;
} }
TextRecordsManager::TextRecordsManager(
LocalFrameView* frame_view,
PaintTimingDetector* paint_timing_detector) {
if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled())
ltp_manager_.emplace(frame_view, paint_timing_detector);
}
void TextRecordsManager::CleanUp() { void TextRecordsManager::CleanUp() {
visible_node_map_.clear(); visible_node_map_.clear();
invisible_node_ids_.clear(); invisible_node_ids_.clear();
texts_queued_for_paint_time_.clear(); texts_queued_for_paint_time_.clear();
CleanUpLargestContentfulPaint(); CleanUpLargestTextPaint();
} }
void TextRecordsManager::Trace(blink::Visitor* visitor) { void TextRecordsManager::Trace(blink::Visitor* visitor) {
visitor->Trace(text_element_timing_); visitor->Trace(text_element_timing_);
visitor->Trace(ltp_manager_);
} }
} // namespace blink } // namespace blink
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "third_party/blink/renderer/core/dom/dom_node_ids.h" #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/paint/text_element_timing.h" #include "third_party/blink/renderer/core/paint/text_element_timing.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/time.h" #include "third_party/blink/renderer/platform/wtf/time.h"
...@@ -43,18 +42,65 @@ class TextRecord : public base::SupportsWeakPtr<TextRecord> { ...@@ -43,18 +42,65 @@ class TextRecord : public base::SupportsWeakPtr<TextRecord> {
DISALLOW_COPY_AND_ASSIGN(TextRecord); DISALLOW_COPY_AND_ASSIGN(TextRecord);
}; };
class TextRecordsManager { class CORE_EXPORT LargestTextPaintManager {
DISALLOW_NEW(); DISALLOW_NEW();
using TextRecordSetComparator = bool (*)(const base::WeakPtr<TextRecord>&, using TextRecordSetComparator = bool (*)(const base::WeakPtr<TextRecord>&,
const base::WeakPtr<TextRecord>&); const base::WeakPtr<TextRecord>&);
using TextRecordSet = using TextRecordSet =
std::set<base::WeakPtr<TextRecord>, TextRecordSetComparator>; std::set<base::WeakPtr<TextRecord>, TextRecordSetComparator>;
friend class TextPaintTimingDetectorTest;
public: public:
TextRecordsManager(); LargestTextPaintManager(LocalFrameView*, PaintTimingDetector*);
inline void RemoveVisibleRecord(base::WeakPtr<TextRecord> record) {
size_ordered_set_.erase(record);
if (cached_largest_paint_candidate_.get() == record.get())
cached_largest_paint_candidate_ = nullptr;
is_result_invalidated_ = true;
}
base::WeakPtr<TextRecord> FindLargestPaintCandidate(); base::WeakPtr<TextRecord> FindLargestPaintCandidate();
void ReportCandidateToTrace(const TextRecord&);
void ReportNoCandidateToTrace();
void UpdateCandidate();
void PopulateTraceValue(TracedValue&, const TextRecord& first_text_paint);
inline void SetCachedResultInvalidated(bool value) {
is_result_invalidated_ = value;
}
inline void InsertRecord(base::WeakPtr<TextRecord> record) {
size_ordered_set_.emplace(record);
SetCachedResultInvalidated(true);
}
void Trace(blink::Visitor*);
private:
friend class LargestContentfulPaintCalculatorTest;
friend class TextPaintTimingDetectorTest;
TextRecordSet size_ordered_set_;
base::WeakPtr<TextRecord> cached_largest_paint_candidate_;
// This is used to cache the largest text paint result for better
// efficiency.
// The result will be invalidated whenever any change is done to the
// variables used in |FindLargestPaintCandidate|.
bool is_result_invalidated_ = false;
unsigned count_candidates_ = 0;
Member<const LocalFrameView> frame_view_;
Member<PaintTimingDetector> paint_timing_detector_;
DISALLOW_COPY_AND_ASSIGN(LargestTextPaintManager);
};
class CORE_EXPORT TextRecordsManager {
DISALLOW_NEW();
friend class TextPaintTimingDetectorTest;
public:
TextRecordsManager(LocalFrameView*, PaintTimingDetector*);
void RemoveVisibleRecord(const LayoutObject&); void RemoveVisibleRecord(const LayoutObject&);
void RemoveInvisibleRecord(const LayoutObject&); void RemoveInvisibleRecord(const LayoutObject&);
inline void RecordInvisibleObject(const LayoutObject& object) { inline void RecordInvisibleObject(const LayoutObject& object) {
...@@ -88,40 +134,39 @@ class TextRecordsManager { ...@@ -88,40 +134,39 @@ class TextRecordsManager {
} }
void CleanUp(); void CleanUp();
void CleanUpLargestTextPaint();
void CleanUpLargestContentfulPaint();
void StopRecordingLargestTextPaint(); void StopRecordingLargestTextPaint();
bool IsRecordingLargestTextPaint() const { return is_recording_ltp_; }
bool HasTextElementTiming() const { return !!text_element_timing_; } bool HasTextElementTiming() const { return text_element_timing_; }
void SetTextElementTiming(TextElementTiming* text_element_timing) { void SetTextElementTiming(TextElementTiming* text_element_timing) {
text_element_timing_ = text_element_timing; text_element_timing_ = text_element_timing;
} }
inline base::Optional<LargestTextPaintManager>& GetLargestTextPaintManager() {
return ltp_manager_;
}
inline bool IsRecordingLargestTextPaint() const {
return ltp_manager_.has_value();
}
void Trace(blink::Visitor*); void Trace(blink::Visitor*);
private: private:
inline void QueueToMeasurePaintTime(base::WeakPtr<TextRecord> record) { friend class LargestContentfulPaintCalculatorTest;
friend class TextPaintTimingDetectorTest;
inline void QueueToMeasurePaintTime(base::WeakPtr<TextRecord>& record) {
texts_queued_for_paint_time_.push_back(std::move(record)); texts_queued_for_paint_time_.push_back(std::move(record));
} }
// This is used to cache the largest text paint result for better efficiency.
// The result will be invalidated whenever any change is done to the variables
// used in |FindLargestPaintCandidate|.
bool is_result_invalidated_ = false;
// This is used to know whether |size_ordered_set_| should be populated or
// not, since this is used by Largest Text Paint but not by Text Element
// Timing.
bool is_recording_ltp_ =
RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled();
// Once LayoutObject* is destroyed, |visible_node_map_| and // Once LayoutObject* is destroyed, |visible_node_map_| and
// |invisible_node_ids_| must immediately clear the corresponding record from // |invisible_node_ids_| must immediately clear the corresponding record from
// themselves. // themselves.
HashMap<const LayoutObject*, std::unique_ptr<TextRecord>> visible_node_map_; HashMap<const LayoutObject*, std::unique_ptr<TextRecord>> visible_node_map_;
HashSet<const LayoutObject*> invisible_node_ids_; HashSet<const LayoutObject*> invisible_node_ids_;
TextRecordSet size_ordered_set_;
Deque<base::WeakPtr<TextRecord>> texts_queued_for_paint_time_; Deque<base::WeakPtr<TextRecord>> texts_queued_for_paint_time_;
base::WeakPtr<TextRecord> cached_largest_paint_candidate_; base::Optional<LargestTextPaintManager> ltp_manager_;
Member<TextElementTiming> text_element_timing_; Member<TextElementTiming> text_element_timing_;
DISALLOW_COPY_AND_ASSIGN(TextRecordsManager); DISALLOW_COPY_AND_ASSIGN(TextRecordsManager);
...@@ -151,49 +196,35 @@ class CORE_EXPORT TextPaintTimingDetector final ...@@ -151,49 +196,35 @@ class CORE_EXPORT TextPaintTimingDetector final
friend class TextPaintTimingDetectorTest; friend class TextPaintTimingDetectorTest;
public: public:
TextPaintTimingDetector(LocalFrameView* frame_view); explicit TextPaintTimingDetector(LocalFrameView*, PaintTimingDetector*);
bool ShouldWalkObject(const LayoutBoxModelObject&) const; bool ShouldWalkObject(const LayoutBoxModelObject&) const;
void RecordAggregatedText(const LayoutBoxModelObject& aggregator, void RecordAggregatedText(const LayoutBoxModelObject& aggregator,
const IntRect& aggregated_visual_rect, const IntRect& aggregated_visual_rect,
const PropertyTreeState&); const PropertyTreeState&);
void OnPaintFinished(); void OnPaintFinished();
void LayoutObjectWillBeDestroyed(const LayoutObject&); void LayoutObjectWillBeDestroyed(const LayoutObject&);
base::WeakPtr<TextRecord> FindLargestPaintCandidate();
void StopRecordEntries(); void StopRecordEntries();
void StopRecordingLargestTextPaint(); void StopRecordingLargestTextPaint();
bool IsRecording() const { return is_recording_; } bool IsRecording() const { return is_recording_; }
bool FinishedReportingText() const { inline bool FinishedReportingText() const { return !is_recording_; }
return !is_recording_ && !need_update_timing_at_frame_end_;
}
void Trace(blink::Visitor*); void Trace(blink::Visitor*);
private: private:
friend class LargestContentfulPaintCalculatorTest; friend class LargestContentfulPaintCalculatorTest;
void PopulateTraceValue(TracedValue&, const TextRecord& first_text_paint);
void TimerFired(TimerBase*);
void UpdateCandidate();
void ReportSwapTime(WebWidgetClient::SwapResult result, void ReportSwapTime(WebWidgetClient::SwapResult result,
base::TimeTicks timestamp); base::TimeTicks timestamp);
void RegisterNotifySwapTime(ReportTimeCallback callback); void RegisterNotifySwapTime(ReportTimeCallback callback);
void ReportCandidateToTrace(const TextRecord&);
void ReportNoCandidateToTrace();
TextRecordsManager records_manager_; TextRecordsManager records_manager_;
// Make sure that at most one swap promise is ongoing. // Make sure that at most one swap promise is ongoing.
bool awaiting_swap_promise_ = false; bool awaiting_swap_promise_ = false;
unsigned count_candidates_ = 0;
bool is_recording_ = true; bool is_recording_ = true;
bool is_recording_ltp_ =
RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled();
bool has_records_changed_ = true;
bool need_update_timing_at_frame_end_ = false; bool need_update_timing_at_frame_end_ = false;
TaskRunnerTimer<TextPaintTimingDetector> timer_; Member<const LocalFrameView> frame_view_;
Member<LocalFrameView> frame_view_;
DISALLOW_COPY_AND_ASSIGN(TextPaintTimingDetector); DISALLOW_COPY_AND_ASSIGN(TextPaintTimingDetector);
}; };
......
...@@ -55,7 +55,8 @@ class TextPaintTimingDetectorTest ...@@ -55,7 +55,8 @@ class TextPaintTimingDetectorTest
wtf_size_t CountRankingSetSize() { wtf_size_t CountRankingSetSize() {
return GetPaintTimingDetector() return GetPaintTimingDetector()
.GetTextPaintTimingDetector() .GetTextPaintTimingDetector()
->records_manager_.size_ordered_set_.size(); ->records_manager_.GetLargestTextPaintManager()
->size_ordered_set_.size();
} }
void InvokeCallback() { void InvokeCallback() {
...@@ -95,10 +96,6 @@ class TextPaintTimingDetectorTest ...@@ -95,10 +96,6 @@ class TextPaintTimingDetectorTest
test_task_runner_->NowTicks()); test_task_runner_->NowTicks());
} }
void UpdateCandidate() {
GetPaintTimingDetector().GetTextPaintTimingDetector()->UpdateCandidate();
}
Element* AppendFontBlockToBody(String content) { Element* AppendFontBlockToBody(String content) {
Element* font = GetDocument().CreateRawElement(html_names::kFontTag); Element* font = GetDocument().CreateRawElement(html_names::kFontTag);
font->setAttribute(html_names::kSizeAttr, AtomicString("5")); font->setAttribute(html_names::kSizeAttr, AtomicString("5"));
...@@ -123,6 +120,7 @@ class TextPaintTimingDetectorTest ...@@ -123,6 +120,7 @@ class TextPaintTimingDetectorTest
return GetFrameView() return GetFrameView()
.GetPaintTimingDetector() .GetPaintTimingDetector()
.GetTextPaintTimingDetector() .GetTextPaintTimingDetector()
->records_manager_.GetLargestTextPaintManager()
->FindLargestPaintCandidate(); ->FindLargestPaintCandidate();
} }
...@@ -130,6 +128,7 @@ class TextPaintTimingDetectorTest ...@@ -130,6 +128,7 @@ class TextPaintTimingDetectorTest
return GetChildFrameView() return GetChildFrameView()
.GetPaintTimingDetector() .GetPaintTimingDetector()
.GetTextPaintTimingDetector() .GetTextPaintTimingDetector()
->records_manager_.GetLargestTextPaintManager()
->FindLargestPaintCandidate(); ->FindLargestPaintCandidate();
} }
...@@ -236,7 +235,6 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) { ...@@ -236,7 +235,6 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) {
<div>small text</div> <div>small text</div>
)HTML"); )HTML");
UpdateAllLifecyclePhasesAndSimulateSwapTime(); UpdateAllLifecyclePhasesAndSimulateSwapTime();
UpdateCandidate();
base::TimeTicks time2 = NowTicks(); base::TimeTicks time2 = NowTicks();
base::TimeTicks first_largest = LargestPaintStoredResult(); base::TimeTicks first_largest = LargestPaintStoredResult();
EXPECT_GE(first_largest, time1); EXPECT_GE(first_largest, time1);
...@@ -244,7 +242,6 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) { ...@@ -244,7 +242,6 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) {
AppendDivElementToBody("a long-long-long text"); AppendDivElementToBody("a long-long-long text");
UpdateAllLifecyclePhasesAndSimulateSwapTime(); UpdateAllLifecyclePhasesAndSimulateSwapTime();
UpdateCandidate();
base::TimeTicks time3 = NowTicks(); base::TimeTicks time3 = NowTicks();
base::TimeTicks second_largest = LargestPaintStoredResult(); base::TimeTicks second_largest = LargestPaintStoredResult();
EXPECT_GE(second_largest, time2); EXPECT_GE(second_largest, time2);
...@@ -335,14 +332,12 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) { ...@@ -335,14 +332,12 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) {
)HTML"); )HTML");
Element* text = AppendDivElementToBody("text to remove"); Element* text = AppendDivElementToBody("text to remove");
UpdateAllLifecyclePhasesAndSimulateSwapTime(); UpdateAllLifecyclePhasesAndSimulateSwapTime();
UpdateCandidate();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(text)); DOMNodeIds::ExistingIdForNode(text));
EXPECT_NE(LargestPaintStoredResult(), base::TimeTicks()); EXPECT_NE(LargestPaintStoredResult(), base::TimeTicks());
RemoveElement(text); RemoveElement(text);
UpdateAllLifecyclePhasesAndSimulateSwapTime(); UpdateAllLifecyclePhasesAndSimulateSwapTime();
UpdateCandidate();
EXPECT_FALSE(TextRecordOfLargestTextPaint()); EXPECT_FALSE(TextRecordOfLargestTextPaint());
EXPECT_EQ(LargestPaintStoredResult(), base::TimeTicks()); EXPECT_EQ(LargestPaintStoredResult(), base::TimeTicks());
} }
......
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