summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc276
1 files changed, 276 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc
new file mode 100644
index 00000000000..0173fe5841e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc
@@ -0,0 +1,276 @@
+// Copyright 2019 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 "third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h"
+
+#include "base/test/simple_test_tick_clock.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/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/platform/graphics/static_bitmap_image.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+namespace blink {
+
+class LargestContentfulPaintCalculatorTest : public RenderingTest {
+ public:
+ using LargestContentType =
+ LargestContentfulPaintCalculator::LargestContentType;
+ void SetUp() override {
+ // Advance the clock so we do not assign null TimeTicks.
+ simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
+ EnableCompositing();
+ RenderingTest::SetUp();
+
+ mock_text_callback_manager_ =
+ MakeGarbageCollected<MockPaintTimingCallbackManager>();
+ GetTextPaintTimingDetector()->ResetCallbackManager(
+ mock_text_callback_manager_);
+ mock_image_callback_manager_ =
+ MakeGarbageCollected<MockPaintTimingCallbackManager>();
+ GetImagePaintTimingDetector()->ResetCallbackManager(
+ 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) {
+ ToHTMLImageElement(GetDocument().getElementById(id))
+ ->SetImageForTest(CreateImageForTest(width, height));
+ }
+
+ ImageResourceContent* CreateImageForTest(int width, int height) {
+ sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
+ SkImageInfo raster_image_info =
+ SkImageInfo::MakeN32Premul(width, height, src_rgb_color_space);
+ sk_sp<SkSurface> surface(SkSurface::MakeRaster(raster_image_info));
+ sk_sp<SkImage> image = surface->makeImageSnapshot();
+ ImageResourceContent* original_image_resource =
+ ImageResourceContent::CreateLoaded(
+ StaticBitmapImage::Create(image).get());
+ return original_image_resource;
+ }
+
+ LargestContentType LastReportedType() {
+ return GetLargestContentfulPaintCalculator()->last_type_;
+ }
+
+ uint64_t LargestImageSize() {
+ return GetLargestContentfulPaintCalculator()->LargestImageSize();
+ }
+
+ uint64_t LargestTextSize() {
+ return GetLargestContentfulPaintCalculator()->LargestTextSize();
+ }
+
+ void UpdateLargestContentfulPaintCandidate() {
+ GetFrame()
+ .View()
+ ->GetPaintTimingDetector()
+ .UpdateLargestContentfulPaintCandidate();
+ }
+
+ void SimulateContentSwapPromise() {
+ mock_text_callback_manager_->InvokeSwapTimeCallback(
+ simulated_clock_.NowTicks());
+ mock_image_callback_manager_->InvokeSwapTimeCallback(
+ simulated_clock_.NowTicks());
+ // Outside the tests, this is invoked by
+ // |PaintTimingCallbackManagerImpl::ReportPaintTime|.
+ UpdateLargestContentfulPaintCandidate();
+ }
+
+ // Outside the tests, the text callback and the image callback are run
+ // together, as in |SimulateContentSwapPromise|.
+ void SimulateImageSwapPromise() {
+ mock_image_callback_manager_->InvokeSwapTimeCallback(
+ simulated_clock_.NowTicks());
+ // Outside the tests, this is invoked by
+ // |PaintTimingCallbackManagerImpl::ReportPaintTime|.
+ UpdateLargestContentfulPaintCandidate();
+ }
+
+ // Outside the tests, the text callback and the image callback are run
+ // together, as in |SimulateContentSwapPromise|.
+ void SimulateTextSwapPromise() {
+ mock_text_callback_manager_->InvokeSwapTimeCallback(
+ simulated_clock_.NowTicks());
+ // Outside the tests, this is invoked by
+ // |PaintTimingCallbackManagerImpl::ReportPaintTime|.
+ UpdateLargestContentfulPaintCandidate();
+ }
+
+ private:
+ LargestContentfulPaintCalculator* GetLargestContentfulPaintCalculator() {
+ return GetFrame()
+ .View()
+ ->GetPaintTimingDetector()
+ .GetLargestContentfulPaintCalculator();
+ }
+
+ base::SimpleTestTickClock simulated_clock_;
+ Persistent<MockPaintTimingCallbackManager> mock_text_callback_manager_;
+ Persistent<MockPaintTimingCallbackManager> mock_image_callback_manager_;
+};
+
+TEST_F(LargestContentfulPaintCalculatorTest, SingleImage) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='target'/>
+ )HTML");
+ SetImage("target", 100, 150);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateImageSwapPromise();
+
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ EXPECT_EQ(LargestImageSize(), 15000u);
+ EXPECT_EQ(LargestTextSize(), 0u);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, SingleText) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <p>This is some text</p>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+ SimulateTextSwapPromise();
+ EXPECT_EQ(LastReportedType(), LargestContentType::kText);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, ImageLargerText) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='target'/>
+ <p>This text should be larger than the image!!!!</p>
+ )HTML");
+ SetImage("target", 3, 3);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateImageSwapPromise();
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ SimulateTextSwapPromise();
+
+ EXPECT_EQ(LastReportedType(), LargestContentType::kText);
+ EXPECT_EQ(LargestImageSize(), 9u);
+ EXPECT_GT(LargestTextSize(), 9u);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, ImageSmallerText) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='target'/>
+ <p>.</p>
+ )HTML");
+ SetImage("target", 100, 200);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateImageSwapPromise();
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ SimulateTextSwapPromise();
+
+ // Text should not be reported, since it is smaller than the image.
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ EXPECT_EQ(LargestImageSize(), 20000u);
+ EXPECT_GT(LargestTextSize(), 0u);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, TextLargerImage) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='target'/>
+ <p>.</p>
+ )HTML");
+ SetImage("target", 100, 200);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateContentSwapPromise();
+
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ EXPECT_EQ(LargestImageSize(), 20000u);
+ EXPECT_GT(LargestTextSize(), 0u);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, TextSmallerImage) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='target'/>
+ <p>This text should be larger than the image!!!!</p>
+ )HTML");
+ SetImage("target", 3, 3);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateContentSwapPromise();
+
+ // Image should not be reported, since it is smaller than the text.
+ EXPECT_EQ(LastReportedType(), LargestContentType::kText);
+ EXPECT_EQ(LargestImageSize(), 9u);
+ EXPECT_GT(LargestTextSize(), 9u);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, LargestImageRemoved) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='large'/>
+ <img id='small'/>
+ <p>Larger than the second image</p>
+ )HTML");
+ SetImage("large", 100, 200);
+ SetImage("small", 3, 3);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateImageSwapPromise();
+ SimulateTextSwapPromise();
+ // Image is larger than the text.
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ EXPECT_EQ(LargestImageSize(), 20000u);
+ EXPECT_GT(LargestTextSize(), 9u);
+
+ GetDocument().getElementById("large")->remove();
+ UpdateAllLifecyclePhasesForTest();
+ // The LCP should now be the text because it is larger than the remaining
+ // image.
+ EXPECT_EQ(LastReportedType(), LargestContentType::kText);
+ EXPECT_EQ(LargestImageSize(), 9u);
+ EXPECT_GT(LargestTextSize(), 9u);
+}
+
+TEST_F(LargestContentfulPaintCalculatorTest, LargestTextRemoved) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <img id='medium'/>
+ <p id='large'>
+ This text element should be larger than than the image!\n
+ These words ensure that this is the case.\n
+ But the image will be larger than the other paragraph!
+ </p>
+ <p id='small'>.</p>
+ )HTML");
+ SetImage("medium", 10, 5);
+ UpdateAllLifecyclePhasesForTest();
+ SimulateImageSwapPromise();
+ SimulateTextSwapPromise();
+ // Test is larger than the image.
+ EXPECT_EQ(LastReportedType(), LargestContentType::kText);
+ EXPECT_EQ(LargestImageSize(), 50u);
+ EXPECT_GT(LargestTextSize(), 50u);
+
+ GetDocument().getElementById("large")->remove();
+ UpdateAllLifecyclePhasesForTest();
+ // The LCP should now be the image because it is larger than the remaining
+ // text.
+ EXPECT_EQ(LastReportedType(), LargestContentType::kImage);
+ EXPECT_EQ(LargestImageSize(), 50u);
+ EXPECT_LT(LargestTextSize(), 50u);
+}
+
+} // namespace blink