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

[LCP] Test: mock swap-time request for text and image

TextPaintTimingDetector(LTP) and ImagePaintTimingDetector (LIP) both
use ChromeClient to register callbacks in their implementation.
However, ChromeClient is an external component, which needs to
be decoupled in the test.

The initial design bypasses the callback in test. Specifically, LIP
bypasses it by having a control flag to direct the callback to a
local callback queue, and LTP simply just ignores the callback logic.
Either approach did not achieve a comprehensive coverage.

The new design in this CL uses a mocking approach for decoupling. As
ChromeClient was called to register callbacks, the new design
inserts an interface between LTP&LIP and ChromeClient. When testing
LTP&LIP, the interface is mocked with a local callback queue.
So the external component can be removed from the unit test.

Compared to an earlier attempt crrev.com/c/1701058 where two callbacks
were combined, this approach allows for separate callback-queueing
for Image/TextPaintTimingDetector, LargestContentfulPaintDetector
and other paint timing components in unit test. This way, future
change in LTP wouldn't affect the unit-test in LIP via ChromeClient
and vice versa. In addition, LargestContentfulPaintCalculator can
thus keep being capable of controlling the order of text callback and
image callback. As ChromeClient is shared with other paint metrics
(FP, FCP, FMP), the tests of LTP and LIP would couple with these
metrics if ChromeClient is not well separated.

As an extra benefit, this change will make it possible to combine
two callbacks by implementing the callback-manager interface in
a different way. The combination will then provide a hook to the
time when "both LIP and LTP callbacks have been invoked". This
hook would make it easy to solve crbug.com/982307.

This CL doesn't change the unit-tests expectations.

Bug: 982307, 987984

Change-Id: I8d58a9676b1b350c630f076c530b54f2d7c6ab04
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1722449Reviewed-by: default avatarSteve Kobes <skobes@chromium.org>
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#682923}
parent c282aada
...@@ -1494,6 +1494,7 @@ jumbo_source_set("unit_tests") { ...@@ -1494,6 +1494,7 @@ jumbo_source_set("unit_tests") {
"paint/paint_property_tree_builder_test.h", "paint/paint_property_tree_builder_test.h",
"paint/paint_property_tree_printer_test.cc", "paint/paint_property_tree_printer_test.cc",
"paint/paint_property_tree_update_tests.cc", "paint/paint_property_tree_update_tests.cc",
"paint/paint_timing_test_helper.h",
"paint/pre_paint_tree_walk_test.cc", "paint/pre_paint_tree_walk_test.cc",
"paint/table_painter_test.cc", "paint/table_painter_test.cc",
"paint/text_paint_timing_detector_test.cc", "paint/text_paint_timing_detector_test.cc",
......
...@@ -5,20 +5,12 @@ ...@@ -5,20 +5,12 @@
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_image_resource.h" #include "third_party/blink/renderer/core/layout/layout_image_resource.h"
#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
#include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h" #include "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/style/style_fetched_image.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
...@@ -69,7 +61,9 @@ static bool LargeImageFirst(const base::WeakPtr<ImageRecord>& a, ...@@ -69,7 +61,9 @@ static bool LargeImageFirst(const base::WeakPtr<ImageRecord>& a,
} }
ImagePaintTimingDetector::ImagePaintTimingDetector(LocalFrameView* frame_view) ImagePaintTimingDetector::ImagePaintTimingDetector(LocalFrameView* frame_view)
: frame_view_(frame_view) {} : frame_view_(frame_view),
callback_manager_(
MakeGarbageCollected<PaintTimingCallbackManagerImpl>()) {}
void ImagePaintTimingDetector::PopulateTraceValue( void ImagePaintTimingDetector::PopulateTraceValue(
TracedValue& value, TracedValue& value,
...@@ -180,20 +174,13 @@ void ImagePaintTimingDetector::RegisterNotifySwapTime() { ...@@ -180,20 +174,13 @@ void ImagePaintTimingDetector::RegisterNotifySwapTime() {
auto callback = CrossThreadBindOnce(&ImagePaintTimingDetector::ReportSwapTime, auto callback = CrossThreadBindOnce(&ImagePaintTimingDetector::ReportSwapTime,
WrapCrossThreadWeakPersistent(this), WrapCrossThreadWeakPersistent(this),
last_registered_frame_index_); last_registered_frame_index_);
if (notify_swap_time_override_for_testing_) {
// Run is not to run the |callback|, but to queue it.
notify_swap_time_override_for_testing_.Run(
ConvertToBaseOnceCallback(std::move(callback)));
num_pending_swap_callbacks_++;
return;
}
// ReportSwapTime on layerTreeView will queue a swap-promise, the callback is // ReportSwapTime on layerTreeView will queue a swap-promise, the callback is
// called when the swap for current render frame completes or fails to happen. // called when the swap for current render frame completes or fails to happen.
LocalFrame& frame = frame_view_->GetFrame(); LocalFrame& frame = frame_view_->GetFrame();
if (!frame.GetPage()) if (!frame.GetPage())
return; return;
frame.GetPage()->GetChromeClient().NotifySwapTime(frame, std::move(callback)); callback_manager_->RegisterCallback(frame, std::move(callback));
num_pending_swap_callbacks_++; num_pending_swap_callbacks_++;
} }
...@@ -339,5 +326,6 @@ ImageRecord* ImageRecordsManager::FindLargestPaintCandidate() const { ...@@ -339,5 +326,6 @@ ImageRecord* ImageRecordsManager::FindLargestPaintCandidate() const {
void ImagePaintTimingDetector::Trace(blink::Visitor* visitor) { void ImagePaintTimingDetector::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_view_); visitor->Trace(frame_view_);
visitor->Trace(callback_manager_);
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "third_party/blink/public/web/web_widget_client.h" #include "third_party/blink/public/web/web_widget_client.h"
#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/loader/resource/image_resource_content.h" #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.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"
...@@ -234,6 +235,9 @@ class CORE_EXPORT ImagePaintTimingDetector final ...@@ -234,6 +235,9 @@ class CORE_EXPORT ImagePaintTimingDetector final
void ReportSwapTime(unsigned last_queued_frame_index, void ReportSwapTime(unsigned last_queued_frame_index,
WebWidgetClient::SwapResult, WebWidgetClient::SwapResult,
base::TimeTicks); base::TimeTicks);
void ResetCallbackManagerForTesting(PaintTimingCallbackManager* manager) {
callback_manager_ = manager;
}
void RegisterNotifySwapTime(); void RegisterNotifySwapTime();
void ReportCandidateToTrace(ImageRecord&); void ReportCandidateToTrace(ImageRecord&);
void ReportNoCandidateToTrace(); void ReportNoCandidateToTrace();
...@@ -241,9 +245,6 @@ class CORE_EXPORT ImagePaintTimingDetector final ...@@ -241,9 +245,6 @@ class CORE_EXPORT ImagePaintTimingDetector final
void UpdateCandidate(); void UpdateCandidate();
base::RepeatingCallback<void(WebWidgetClient::ReportTimeCallback)>
notify_swap_time_override_for_testing_;
// Used to find the last candidate. // Used to find the last candidate.
unsigned count_candidates_ = 0; unsigned count_candidates_ = 0;
...@@ -265,6 +266,7 @@ class CORE_EXPORT ImagePaintTimingDetector final ...@@ -265,6 +266,7 @@ class CORE_EXPORT ImagePaintTimingDetector final
ImageRecordsManager records_manager_; ImageRecordsManager records_manager_;
Member<LocalFrameView> frame_view_; Member<LocalFrameView> frame_view_;
Member<PaintTimingCallbackManager> callback_manager_;
}; };
} // namespace blink } // namespace blink
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/paint_timing_test_helper.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/core/svg/svg_image_element.h" #include "third_party/blink/renderer/core/svg/svg_image_element.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
...@@ -35,8 +36,6 @@ namespace blink { ...@@ -35,8 +36,6 @@ namespace blink {
class ImagePaintTimingDetectorTest class ImagePaintTimingDetectorTest
: public testing::Test, : public testing::Test,
private ScopedFirstContentfulPaintPlusPlusForTest { private ScopedFirstContentfulPaintPlusPlusForTest {
using CallbackQueue = std::queue<WebWidgetClient::ReportTimeCallback>;
public: public:
ImagePaintTimingDetectorTest() ImagePaintTimingDetectorTest()
: ScopedFirstContentfulPaintPlusPlusForTest(true), : ScopedFirstContentfulPaintPlusPlusForTest(true),
...@@ -85,12 +84,6 @@ class ImagePaintTimingDetectorTest ...@@ -85,12 +84,6 @@ class ImagePaintTimingDetectorTest
return scrollable_area->VisibleContentRect(); return scrollable_area->VisibleContentRect();
} }
void ReplaceCallBackQueue(PaintTimingDetector& detector) {
detector.GetImagePaintTimingDetector()
->notify_swap_time_override_for_testing_ =
base::BindRepeating(&ImagePaintTimingDetectorTest::FakeNotifySwapTime,
base::Unretained(this));
}
ImageRecord* FindLargestPaintCandidate() { ImageRecord* FindLargestPaintCandidate() {
return GetPaintTimingDetector() return GetPaintTimingDetector()
.GetImagePaintTimingDetector() .GetImagePaintTimingDetector()
...@@ -171,15 +164,19 @@ class ImagePaintTimingDetectorTest ...@@ -171,15 +164,19 @@ class ImagePaintTimingDetectorTest
void UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() { void UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() {
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
SimulatePassOfTime(); SimulatePassOfTime();
if (!callback_queue_.empty()) while (mock_callback_manager_->CountCallbacks() > 0)
InvokeCallback(); InvokeSwapTimeCallback(mock_callback_manager_);
} }
void SetBodyInnerHTML(const std::string& content) { void SetBodyInnerHTML(const std::string& content) {
frame_test_helpers::LoadHTMLString( frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), content, web_view_helper_.GetWebView()->MainFrameImpl(), content,
KURL("http://test.com")); KURL("http://test.com"));
ReplaceCallBackQueue(GetPaintTimingDetector()); mock_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetPaintTimingDetector()
.GetImagePaintTimingDetector()
->ResetCallbackManagerForTesting(mock_callback_manager_);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
} }
...@@ -187,15 +184,28 @@ class ImagePaintTimingDetectorTest ...@@ -187,15 +184,28 @@ class ImagePaintTimingDetectorTest
GetChildDocument()->SetBaseURLOverride(KURL("http://test.com")); GetChildDocument()->SetBaseURLOverride(KURL("http://test.com"));
GetChildDocument()->body()->SetInnerHTMLFromString(content, GetChildDocument()->body()->SetInnerHTMLFromString(content,
ASSERT_NO_EXCEPTION); ASSERT_NO_EXCEPTION);
child_mock_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetChildPaintTimingDetector()
.GetImagePaintTimingDetector()
->ResetCallbackManagerForTesting(child_mock_callback_manager_);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
} }
void InvokeCallback() { void InvokeCallback() {
DCHECK_GT(callback_queue_.size(), 0UL); DCHECK_GT(mock_callback_manager_->CountCallbacks(), 0UL);
std::move(callback_queue_.front()) InvokeSwapTimeCallback(mock_callback_manager_);
.Run(WebWidgetClient::SwapResult::kDidSwap, }
test_task_runner_->NowTicks());
callback_queue_.pop(); void InvokeChildFrameCallback() {
DCHECK_GT(child_mock_callback_manager_->CountCallbacks(), 0UL);
InvokeSwapTimeCallback(child_mock_callback_manager_);
}
void InvokeSwapTimeCallback(
MockPaintTimingCallbackManager* image_callback_manager) {
image_callback_manager->InvokeSwapTimeCallback(
test_task_runner_->NowTicks());
} }
void SetImageAndPaint(AtomicString id, int width, int height) { void SetImageAndPaint(AtomicString id, int width, int height) {
...@@ -241,9 +251,6 @@ class ImagePaintTimingDetectorTest ...@@ -241,9 +251,6 @@ class ImagePaintTimingDetectorTest
LocalFrame* GetChildFrame() { LocalFrame* GetChildFrame() {
return To<LocalFrame>(GetFrame()->Tree().FirstChild()); return To<LocalFrame>(GetFrame()->Tree().FirstChild());
} }
void FakeNotifySwapTime(WebWidgetClient::ReportTimeCallback callback) {
callback_queue_.push(std::move(callback));
}
ImageResourceContent* CreateImageForTest(int width, int height) { ImageResourceContent* CreateImageForTest(int width, int height) {
sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB(); sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
SkImageInfo raster_image_info = SkImageInfo raster_image_info =
...@@ -257,6 +264,8 @@ class ImagePaintTimingDetectorTest ...@@ -257,6 +264,8 @@ class ImagePaintTimingDetectorTest
} }
CallbackQueue callback_queue_; CallbackQueue callback_queue_;
Persistent<MockPaintTimingCallbackManager> mock_callback_manager_;
Persistent<MockPaintTimingCallbackManager> child_mock_callback_manager_;
}; };
constexpr base::TimeDelta ImagePaintTimingDetectorTest::kQuantumOfTime; constexpr base::TimeDelta ImagePaintTimingDetectorTest::kQuantumOfTime;
...@@ -996,13 +1005,12 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe) { ...@@ -996,13 +1005,12 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe) {
<style>img { display:block }</style> <style>img { display:block }</style>
<img id="target"></img> <img id="target"></img>
)HTML"); )HTML");
ReplaceCallBackQueue(GetChildPaintTimingDetector());
SetChildFrameImageAndPaint("target", 5, 5); SetChildFrameImageAndPaint("target", 5, 5);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
// Ensure main frame doesn't capture this image. // Ensure main frame doesn't capture this image.
EXPECT_EQ(CountVisibleImageRecords(), 0u); EXPECT_EQ(CountVisibleImageRecords(), 0u);
EXPECT_EQ(CountChildFrameRecords(), 1u); EXPECT_EQ(CountChildFrameRecords(), 1u);
InvokeCallback(); InvokeChildFrameCallback();
ImageRecord* image = FindChildFrameLargestPaintCandidate(); ImageRecord* image = FindChildFrameLargestPaintCandidate();
EXPECT_TRUE(image); EXPECT_TRUE(image);
// Ensure the image size is not clipped (5*5). // Ensure the image size is not clipped (5*5).
...@@ -1022,7 +1030,6 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe_ClippedByMainFrameViewport) { ...@@ -1022,7 +1030,6 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe_ClippedByMainFrameViewport) {
)HTML"); )HTML");
// Make sure the iframe is out of main-frame's viewport. // Make sure the iframe is out of main-frame's viewport.
DCHECK_LT(GetViewportRect(GetFrameView()).Height(), 1234567); DCHECK_LT(GetViewportRect(GetFrameView()).Height(), 1234567);
ReplaceCallBackQueue(GetChildPaintTimingDetector());
SetChildFrameImageAndPaint("target", 5, 5); SetChildFrameImageAndPaint("target", 5, 5);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
EXPECT_EQ(CountVisibleImageRecords(), 0u); EXPECT_EQ(CountVisibleImageRecords(), 0u);
...@@ -1039,12 +1046,11 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe_HalfClippedByMainFrameViewport) { ...@@ -1039,12 +1046,11 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe_HalfClippedByMainFrameViewport) {
<style>img { display:block }</style> <style>img { display:block }</style>
<img id="target"></img> <img id="target"></img>
)HTML"); )HTML");
ReplaceCallBackQueue(GetChildPaintTimingDetector());
SetChildFrameImageAndPaint("target", 10, 10); SetChildFrameImageAndPaint("target", 10, 10);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
EXPECT_EQ(CountVisibleImageRecords(), 0u); EXPECT_EQ(CountVisibleImageRecords(), 0u);
EXPECT_EQ(CountChildFrameRecords(), 1u); EXPECT_EQ(CountChildFrameRecords(), 1u);
InvokeCallback(); InvokeChildFrameCallback();
ImageRecord* image = FindChildFrameLargestPaintCandidate(); ImageRecord* image = FindChildFrameLargestPaintCandidate();
EXPECT_TRUE(image); EXPECT_TRUE(image);
EXPECT_LT(image->first_size, 100ul); EXPECT_LT(image->first_size, 100ul);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/paint_timing_test_helper.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImage.h"
...@@ -22,6 +23,28 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest { ...@@ -22,6 +23,28 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(100)); simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
EnableCompositing(); EnableCompositing();
RenderingTest::SetUp(); RenderingTest::SetUp();
mock_text_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetTextPaintTimingDetector()->ResetCallbackManagerForTesting(
mock_text_callback_manager_);
mock_image_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetImagePaintTimingDetector()->ResetCallbackManagerForTesting(
mock_image_callback_manager_);
}
ImagePaintTimingDetector* GetImagePaintTimingDetector() {
return GetFrame()
.View()
->GetPaintTimingDetector()
.GetImagePaintTimingDetector();
}
TextPaintTimingDetector* GetTextPaintTimingDetector() {
return GetFrame()
.View()
->GetPaintTimingDetector()
.GetTextPaintTimingDetector();
} }
void SetImage(const char* id, int width, int height) { void SetImage(const char* id, int width, int height) {
...@@ -60,22 +83,13 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest { ...@@ -60,22 +83,13 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
} }
void SimulateImageSwapPromise() { void SimulateImageSwapPromise() {
auto* image_detector = GetFrame() mock_image_callback_manager_->InvokeSwapTimeCallback(
.View() simulated_clock_.NowTicks());
->GetPaintTimingDetector()
.GetImagePaintTimingDetector();
image_detector->ReportSwapTime(image_detector->last_registered_frame_index_,
WebWidgetClient::SwapResult::kDidSwap,
simulated_clock_.NowTicks());
} }
void SimulateTextSwapPromise() { void SimulateTextSwapPromise() {
auto* text_detector = GetFrame() mock_text_callback_manager_->InvokeSwapTimeCallback(
.View() simulated_clock_.NowTicks());
->GetPaintTimingDetector()
.GetTextPaintTimingDetector();
text_detector->ReportSwapTime(WebWidgetClient::SwapResult::kDidSwap,
simulated_clock_.NowTicks());
} }
private: private:
...@@ -87,6 +101,8 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest { ...@@ -87,6 +101,8 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
} }
base::SimpleTestTickClock simulated_clock_; base::SimpleTestTickClock simulated_clock_;
Persistent<MockPaintTimingCallbackManager> mock_text_callback_manager_;
Persistent<MockPaintTimingCallbackManager> mock_image_callback_manager_;
}; };
TEST_F(LargestContentfulPaintCalculatorTest, SingleImage) { TEST_F(LargestContentfulPaintCalculatorTest, SingleImage) {
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h" #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h" #include "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
...@@ -25,6 +27,7 @@ ...@@ -25,6 +27,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h" #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h" #include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink { namespace blink {
...@@ -327,4 +330,10 @@ void PaintTimingDetector::Trace(Visitor* visitor) { ...@@ -327,4 +330,10 @@ void PaintTimingDetector::Trace(Visitor* visitor) {
visitor->Trace(largest_contentful_paint_calculator_); visitor->Trace(largest_contentful_paint_calculator_);
} }
void PaintTimingCallbackManagerImpl::RegisterCallback(
LocalFrame& frame,
ReportTimeCallback callback) {
frame.GetPage()->GetChromeClient().NotifySwapTime(frame, std::move(callback));
}
} // namespace blink } // namespace blink
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
#include "third_party/blink/public/platform/web_input_event.h" #include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink { namespace blink {
...@@ -23,6 +25,37 @@ class PropertyTreeState; ...@@ -23,6 +25,37 @@ class PropertyTreeState;
class TextPaintTimingDetector; class TextPaintTimingDetector;
struct WebFloatRect; struct WebFloatRect;
using ReportTimeCallback =
WTF::CrossThreadOnceFunction<void(WebWidgetClient::SwapResult,
base::TimeTicks)>;
// |PaintTimingCallbackManager| is an interface between
// |ImagePaintTimingDetector|/|TextPaintTimingDetector| and |ChromeClient|.
// As |ChromeClient| is shared among the paint-timing-detecters, it
// makes it hard to test each detector without being affected other detectors.
// The interface, however, allows unit tests to mock |ChromeClient| for each
// detector. With the mock, |ImagePaintTimingDetector|'s callback does not need
// to store in the same queue as |TextPaintTimingDetector|'s. The separate
// queue makes it possible to pop an |ImagePaintTimingDetector|'s callback
// without having to popping the |TextPaintTimingDetector|'s.
class PaintTimingCallbackManager : public GarbageCollectedMixin {
public:
virtual void RegisterCallback(LocalFrame&, ReportTimeCallback) = 0;
};
using ReportTimeCallback =
WTF::CrossThreadOnceFunction<void(WebWidgetClient::SwapResult,
base::TimeTicks)>;
class PaintTimingCallbackManagerImpl
: public GarbageCollected<PaintTimingCallbackManagerImpl>,
public PaintTimingCallbackManager {
USING_GARBAGE_COLLECTED_MIXIN(PaintTimingCallbackManagerImpl);
public:
void RegisterCallback(LocalFrame&, ReportTimeCallback) override;
void Trace(Visitor* visitor) override {}
};
// PaintTimingDetector contains some of paint metric detectors, // PaintTimingDetector contains some of paint metric detectors,
// providing common infrastructure for these detectors. // providing common infrastructure for these detectors.
// //
......
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_TEST_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_TEST_HELPER_H_
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
namespace blink {
using CallbackQueue = std::queue<WebWidgetClient::ReportTimeCallback>;
// |MockPaintTimingCallbackManager| is used to mock
// |ChromeClient::NotifySwapTime()|'s swap-time queueing and invoking for
// unit-tests. Find more details in |PaintTimingCallbackManager|.
class MockPaintTimingCallbackManager final
: public GarbageCollectedFinalized<MockPaintTimingCallbackManager>,
public PaintTimingCallbackManager {
USING_GARBAGE_COLLECTED_MIXIN(MockPaintTimingCallbackManager);
public:
~MockPaintTimingCallbackManager() {}
void RegisterCallback(LocalFrame& frame,
ReportTimeCallback callback) override {
callback_queue_.push(ConvertToBaseOnceCallback(std::move(callback)));
}
void InvokeSwapTimeCallback(base::TimeTicks swap_time) {
DCHECK_GT(callback_queue_.size(), 0UL);
std::move(callback_queue_.front())
.Run(WebWidgetClient::SwapResult::kDidSwap, swap_time);
callback_queue_.pop();
}
size_t CountCallbacks() { return callback_queue_.size(); }
void Trace(Visitor* visitor) override {}
private:
CallbackQueue callback_queue_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_TEST_HELPER_H_
...@@ -8,20 +8,11 @@ ...@@ -8,20 +8,11 @@
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h" #include "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink { namespace blink {
...@@ -44,6 +35,7 @@ TextPaintTimingDetector::TextPaintTimingDetector( ...@@ -44,6 +35,7 @@ TextPaintTimingDetector::TextPaintTimingDetector(
LocalFrameView* frame_view, LocalFrameView* frame_view,
PaintTimingDetector* paint_timing_detector) PaintTimingDetector* paint_timing_detector)
: records_manager_(frame_view, paint_timing_detector), : records_manager_(frame_view, paint_timing_detector),
callback_manager_(MakeGarbageCollected<PaintTimingCallbackManagerImpl>()),
frame_view_(frame_view) {} frame_view_(frame_view) {}
void LargestTextPaintManager::PopulateTraceValue( void LargestTextPaintManager::PopulateTraceValue(
...@@ -145,7 +137,7 @@ void TextPaintTimingDetector::RegisterNotifySwapTime( ...@@ -145,7 +137,7 @@ void TextPaintTimingDetector::RegisterNotifySwapTime(
LocalFrame& frame = frame_view_->GetFrame(); LocalFrame& frame = frame_view_->GetFrame();
if (!frame.GetPage()) if (!frame.GetPage())
return; return;
frame.GetPage()->GetChromeClient().NotifySwapTime(frame, std::move(callback)); callback_manager_->RegisterCallback(frame, std::move(callback));
awaiting_swap_promise_ = true; awaiting_swap_promise_ = true;
} }
...@@ -230,6 +222,7 @@ void TextPaintTimingDetector::StopRecordingLargestTextPaint() { ...@@ -230,6 +222,7 @@ void TextPaintTimingDetector::StopRecordingLargestTextPaint() {
void TextPaintTimingDetector::Trace(blink::Visitor* visitor) { void TextPaintTimingDetector::Trace(blink::Visitor* visitor) {
visitor->Trace(records_manager_); visitor->Trace(records_manager_);
visitor->Trace(frame_view_); visitor->Trace(frame_view_);
visitor->Trace(callback_manager_);
} }
LargestTextPaintManager::LargestTextPaintManager( LargestTextPaintManager::LargestTextPaintManager(
......
...@@ -11,11 +11,10 @@ ...@@ -11,11 +11,10 @@
#include "third_party/blink/public/web/web_widget_client.h" #include "third_party/blink/public/web/web_widget_client.h"
#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/paint_timing_detector.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/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/vector.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink { namespace blink {
...@@ -219,9 +218,14 @@ class CORE_EXPORT TextPaintTimingDetector final ...@@ -219,9 +218,14 @@ class CORE_EXPORT TextPaintTimingDetector final
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 ResetCallbackManagerForTesting(PaintTimingCallbackManager* manager) {
callback_manager_ = manager;
}
TextRecordsManager records_manager_; TextRecordsManager records_manager_;
Member<PaintTimingCallbackManager> callback_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;
bool is_recording_ = true; bool is_recording_ = true;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/paint_timing_test_helper.h"
#include "third_party/blink/renderer/core/svg/svg_text_content_element.h" #include "third_party/blink/renderer/core/svg/svg_text_content_element.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
...@@ -69,6 +70,12 @@ class TextPaintTimingDetectorTest ...@@ -69,6 +70,12 @@ class TextPaintTimingDetectorTest
return GetPaintTimingDetector().GetTextPaintTimingDetector(); return GetPaintTimingDetector().GetTextPaintTimingDetector();
} }
TextPaintTimingDetector* GetChildFrameTextPaintTimingDetector() {
return GetChildFrameView()
.GetPaintTimingDetector()
.GetTextPaintTimingDetector();
}
base::Optional<LargestTextPaintManager>& GetLargestTextPaintManager() { base::Optional<LargestTextPaintManager>& GetLargestTextPaintManager() {
return GetTextPaintTimingDetector() return GetTextPaintTimingDetector()
->records_manager_.GetLargestTextPaintManager(); ->records_manager_.GetLargestTextPaintManager();
...@@ -107,10 +114,18 @@ class TextPaintTimingDetectorTest ...@@ -107,10 +114,18 @@ class TextPaintTimingDetectorTest
} }
void InvokeCallback() { void InvokeCallback() {
TextPaintTimingDetector* detector = DCHECK_GT(mock_callback_manager_->CountCallbacks(), 0u);
GetPaintTimingDetector().GetTextPaintTimingDetector(); InvokeSwapTimeCallback(mock_callback_manager_);
detector->ReportSwapTime(WebWidgetClient::SwapResult::kDidSwap, }
test_task_runner_->NowTicks());
void ChildFrameSwapTimeCallBack() {
DCHECK_GT(child_frame_mock_callback_manager_->CountCallbacks(), 0u);
InvokeSwapTimeCallback(child_frame_mock_callback_manager_);
}
void InvokeSwapTimeCallback(
MockPaintTimingCallbackManager* callback_manager) {
callback_manager->InvokeSwapTimeCallback(test_task_runner_->NowTicks());
} }
base::TimeTicks LargestPaintStoredResult() { base::TimeTicks LargestPaintStoredResult() {
...@@ -121,6 +136,10 @@ class TextPaintTimingDetectorTest ...@@ -121,6 +136,10 @@ class TextPaintTimingDetectorTest
frame_test_helpers::LoadHTMLString( frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), content, web_view_helper_.GetWebView()->MainFrameImpl(), content,
KURL("http://test.com")); KURL("http://test.com"));
mock_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetTextPaintTimingDetector()->ResetCallbackManagerForTesting(
mock_callback_manager_);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
} }
...@@ -128,6 +147,10 @@ class TextPaintTimingDetectorTest ...@@ -128,6 +147,10 @@ class TextPaintTimingDetectorTest
GetChildDocument()->SetBaseURLOverride(KURL("http://test.com")); GetChildDocument()->SetBaseURLOverride(KURL("http://test.com"));
GetChildDocument()->body()->SetInnerHTMLFromString(content, GetChildDocument()->body()->SetInnerHTMLFromString(content,
ASSERT_NO_EXCEPTION); ASSERT_NO_EXCEPTION);
child_frame_mock_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetChildFrameTextPaintTimingDetector()->ResetCallbackManagerForTesting(
child_frame_mock_callback_manager_);
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
} }
...@@ -139,13 +162,8 @@ class TextPaintTimingDetectorTest ...@@ -139,13 +162,8 @@ class TextPaintTimingDetectorTest
// This only triggers ReportSwapTime in main frame. // This only triggers ReportSwapTime in main frame.
void UpdateAllLifecyclePhasesAndSimulateSwapTime() { void UpdateAllLifecyclePhasesAndSimulateSwapTime() {
UpdateAllLifecyclePhases(); UpdateAllLifecyclePhases();
TextPaintTimingDetector* detector = while (mock_callback_manager_->CountCallbacks() > 0)
GetPaintTimingDetector().GetTextPaintTimingDetector(); InvokeCallback();
if (detector &&
!detector->records_manager_.texts_queued_for_paint_time_.empty()) {
detector->ReportSwapTime(WebWidgetClient::SwapResult::kDidSwap,
test_task_runner_->NowTicks());
}
} }
size_t CountPendingSwapTime(LocalFrameView& frame_view) { size_t CountPendingSwapTime(LocalFrameView& frame_view) {
...@@ -154,14 +172,6 @@ class TextPaintTimingDetectorTest ...@@ -154,14 +172,6 @@ class TextPaintTimingDetectorTest
return detector->records_manager_.texts_queued_for_paint_time_.size(); return detector->records_manager_.texts_queued_for_paint_time_.size();
} }
void ChildFrameSwapTimeCallBack() {
GetChildFrameView()
.GetPaintTimingDetector()
.GetTextPaintTimingDetector()
->ReportSwapTime(WebWidgetClient::SwapResult::kDidSwap,
test_task_runner_->NowTicks());
}
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"));
...@@ -227,6 +237,8 @@ class TextPaintTimingDetectorTest ...@@ -227,6 +237,8 @@ class TextPaintTimingDetectorTest
frame_test_helpers::WebViewHelper web_view_helper_; frame_test_helpers::WebViewHelper web_view_helper_;
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_; scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
Persistent<MockPaintTimingCallbackManager> mock_callback_manager_;
Persistent<MockPaintTimingCallbackManager> child_frame_mock_callback_manager_;
}; };
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_NoText) { TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_NoText) {
......
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