Commit 47b7a698 authored by Nicolás Peña Moreno's avatar Nicolás Peña Moreno Committed by Commit Bot

[LCP] Scale rects by device pixel ratio

Bug: 981392, 965505
Change-Id: Ie714ae1a869e858f2051c29a6733d3468c3ebf51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1707056Reviewed-by: default avatarSteve Kobes <skobes@chromium.org>
Commit-Queue: Nicolás Peña Moreno <npm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#678839}
parent bad08fff
......@@ -197,8 +197,10 @@ class CORE_EXPORT HTMLVideoElement final : public HTMLMediaElement,
void SetIsEffectivelyFullscreen(blink::WebFullscreenVideoStatus);
void SetImageForTest(ImageResourceContent* content) {
DCHECK(image_loader_);
if (!image_loader_)
image_loader_ = MakeGarbageCollected<HTMLImageLoader>(this);
image_loader_->SetImageForTest(content);
SetDisplayMode(kPoster);
}
VideoWakeLock* wake_lock_for_tests() const { return wake_lock_; }
......
......@@ -267,9 +267,13 @@ void ImagePaintTimingDetector::RecordImage(
.CalculateVisualRect(visual_rect, current_paint_chunk_properties)
.Size()
.Area();
// Transform visual rect to window before calling downscale.
WebFloatRect float_visual_rect = FloatRect(visual_rect);
frame_view_->GetPaintTimingDetector().ConvertViewportToWindow(
&float_visual_rect);
rect_size = DownScaleIfIntrinsicSizeIsSmaller(
rect_size, intrinsic_size.Area(), visual_rect.Size().Area());
rect_size, intrinsic_size.Area(),
float_visual_rect.width * float_visual_rect.height);
if (rect_size == 0) {
records_manager_.RecordInvisible(node_id);
} else {
......
......@@ -7,6 +7,8 @@
#include "third_party/blink/renderer/core/dom/document.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/web_frame_widget_base.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
......@@ -235,6 +237,18 @@ void PaintTimingDetector::DidChangePerformanceTiming() {
loader->DidChangePerformanceTiming();
}
void PaintTimingDetector::ConvertViewportToWindow(
WebFloatRect* float_rect) const {
WebLocalFrameImpl* web_frame =
WebLocalFrameImpl::FromFrame(&frame_view_->GetFrame());
// May be nullptr in some tests.
if (!web_frame)
return;
WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget();
DCHECK(widget);
widget->Client()->ConvertViewportToWindow(float_rect);
}
FloatRect PaintTimingDetector::CalculateVisualRect(
const IntRect& visual_rect,
const PropertyTreeState& current_paint_chunk_properties) const {
......@@ -247,9 +261,11 @@ FloatRect PaintTimingDetector::CalculateVisualRect(
GeometryMapper::LocalToAncestorVisualRect(current_paint_chunk_properties,
PropertyTreeState::Root(),
float_clip_visual_rect);
FloatRect& float_visual_rect = float_clip_visual_rect.Rect();
if (frame_view_->GetFrame().LocalFrameRoot().IsMainFrame())
WebFloatRect float_visual_rect = float_clip_visual_rect.Rect();
if (frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()) {
ConvertViewportToWindow(&float_visual_rect);
return float_visual_rect;
}
// OOPIF. The final rect lives in the iframe's root frame space. We need to
// project it to the top frame space.
auto layout_visual_rect = PhysicalRect::EnclosingRect(float_visual_rect);
......@@ -257,7 +273,9 @@ FloatRect PaintTimingDetector::CalculateVisualRect(
.LocalFrameRoot()
.View()
->MapToVisualRectInTopFrameSpace(layout_visual_rect);
return FloatRect(layout_visual_rect);
WebFloatRect float_rect = FloatRect(layout_visual_rect);
ConvertViewportToWindow(&float_rect);
return float_rect;
}
ScopedPaintTimingDetectorBlockPaintHook*
......
......@@ -21,6 +21,7 @@ class LayoutObject;
class LocalFrameView;
class PropertyTreeState;
class TextPaintTimingDetector;
struct WebFloatRect;
// PaintTimingDetector contains some of paint metric detectors,
// providing common infrastructure for these detectors.
......@@ -67,6 +68,7 @@ class CORE_EXPORT PaintTimingDetector
return tracing_enabled;
}
void ConvertViewportToWindow(WebFloatRect* float_rect) const;
FloatRect CalculateVisualRect(const IntRect& visual_rect,
const PropertyTreeState&) const;
......
......@@ -6,6 +6,8 @@
#include "base/test/test_mock_time_task_runner.h"
#include "base/test/trace_event_analyzer.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/paint/paint_timing_detector.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"
......@@ -15,25 +17,38 @@
namespace blink {
class TextPaintTimingDetectorTest
: public RenderingTest,
: public testing::Test,
private ScopedFirstContentfulPaintPlusPlusForTest {
public:
TextPaintTimingDetectorTest()
: RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()),
ScopedFirstContentfulPaintPlusPlusForTest(true) {}
: ScopedFirstContentfulPaintPlusPlusForTest(true),
test_task_runner_(
base::MakeRefCounted<base::TestMockTimeTaskRunner>()) {}
void SetUp() override {
RenderingTest::SetUp();
RenderingTest::EnableCompositing();
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
web_view_helper_.Initialize();
WebLocalFrameImpl& frame_impl = *web_view_helper_.LocalMainFrame();
frame_impl.ViewImpl()->MainFrameWidget()->Resize(WebSize(640, 480));
frame_test_helpers::LoadFrame(
web_view_helper_.GetWebView()->MainFrameImpl(), "about:blank");
// Enable compositing on the page.
web_view_helper_.GetWebView()
->GetPage()
->GetSettings()
.SetAcceleratedCompositingEnabled(true);
GetDocument().View()->SetParentVisible(true);
GetDocument().View()->SetSelfVisible(true);
// Advance clock so it isn't 0 as rendering code asserts in that case.
AdvanceClock(base::TimeDelta::FromMicroseconds(1));
}
protected:
LocalFrameView& GetFrameView() { return *GetFrame().View(); }
LocalFrameView& GetFrameView() { return *GetFrame()->View(); }
PaintTimingDetector& GetPaintTimingDetector() {
return GetFrameView().GetPaintTimingDetector();
}
Document& GetDocument() { return *GetFrame()->GetDocument(); }
IntRect GetViewportRect(LocalFrameView& view) {
ScrollableArea* scrollable_area = view.GetScrollableArea();
......@@ -41,7 +56,12 @@ class TextPaintTimingDetectorTest
return scrollable_area->VisibleContentRect();
}
LocalFrameView& GetChildFrameView() { return *ChildFrame().View(); }
LocalFrameView& GetChildFrameView() {
return *To<LocalFrame>(GetFrame()->Tree().FirstChild())->View();
}
Document* GetChildDocument() {
return To<LocalFrame>(GetFrame()->Tree().FirstChild())->GetDocument();
}
TextPaintTimingDetector* GetTextPaintTimingDetector() {
return GetPaintTimingDetector().GetTextPaintTimingDetector();
......@@ -95,9 +115,28 @@ class TextPaintTimingDetectorTest
return GetPaintTimingDetector().largest_text_paint_time_;
}
void SetBodyInnerHTML(const std::string& content) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), content,
KURL("http://test.com"));
UpdateAllLifecyclePhases();
}
void SetChildBodyInnerHTML(const String& content) {
GetChildDocument()->SetBaseURLOverride(KURL("http://test.com"));
GetChildDocument()->body()->SetInnerHTMLFromString(content,
ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhases();
}
void UpdateAllLifecyclePhases() {
GetDocument().View()->UpdateAllLifecyclePhases(
DocumentLifecycle::LifecycleUpdateReason::kTest);
}
// This only triggers ReportSwapTime in main frame.
void UpdateAllLifecyclePhasesAndSimulateSwapTime() {
UpdateAllLifecyclePhasesForTest();
UpdateAllLifecyclePhases();
TextPaintTimingDetector* detector =
GetPaintTimingDetector().GetTextPaintTimingDetector();
if (detector &&
......@@ -177,7 +216,14 @@ class TextPaintTimingDetectorTest
test_task_runner_->FastForwardBy(delta);
}
void LoadAhem() { web_view_helper_.LoadAhem(); }
private:
LocalFrame* GetFrame() {
return web_view_helper_.GetWebView()->MainFrameImpl()->GetFrame();
}
frame_test_helpers::WebViewHelper web_view_helper_;
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
};
......@@ -257,7 +303,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_TraceEvent_NoCandidate) {
Element* element = AppendDivElementToBody("text");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
RemoveElement(element);
UpdateAllLifecyclePhasesForTest();
UpdateAllLifecyclePhases();
}
auto analyzer = trace_analyzer::Stop();
trace_analyzer::TraceEventVector events;
......@@ -318,7 +364,7 @@ TEST_F(TextPaintTimingDetectorTest, NodeRemovedBeforeAssigningSwapTime) {
<div id="remove">The only text</div>
</div>
)HTML");
UpdateAllLifecyclePhasesForTest();
UpdateAllLifecyclePhases();
GetDocument().getElementById("parent")->RemoveChild(
GetDocument().getElementById("remove"));
InvokeCallback();
......@@ -655,8 +701,8 @@ TEST_F(TextPaintTimingDetectorTest, Iframe) {
SetBodyInnerHTML(R"HTML(
<iframe width=100px height=100px></iframe>
)HTML");
SetChildFrameHTML("A");
UpdateAllLifecyclePhasesForTest();
SetChildBodyInnerHTML("A");
UpdateAllLifecyclePhases();
EXPECT_EQ(CountPendingSwapTime(GetChildFrameView()), 1u);
ChildFrameSwapTimeCallBack();
base::WeakPtr<TextRecord> text = ChildFrameTextRecordOfLargestTextPaint();
......@@ -667,14 +713,14 @@ TEST_F(TextPaintTimingDetectorTest, Iframe_ClippedByViewport) {
SetBodyInnerHTML(R"HTML(
<iframe width=100px height=100px></iframe>
)HTML");
SetChildFrameHTML(R"HTML(
SetChildBodyInnerHTML(R"HTML(
<style>
#d { margin-top: 200px }
</style>
<div id='d'>text</div>
)HTML");
DCHECK_EQ(GetViewportRect(GetChildFrameView()).Height(), 100);
UpdateAllLifecyclePhasesForTest();
UpdateAllLifecyclePhases();
EXPECT_EQ(CountPendingSwapTime(GetChildFrameView()), 0u);
}
......
......@@ -347,6 +347,16 @@
"base": "external/wpt/element-timing",
"args": ["--force-device-scale-factor=2", "--enable-use-zoom-for-dsf=false"]
},
{
"prefix": "scalefactor200",
"base": "external/wpt/largest-contentful-paint",
"args": ["--force-device-scale-factor=2"]
},
{
"prefix": "scalefactor200withoutzoom",
"base": "external/wpt/largest-contentful-paint",
"args": ["--force-device-scale-factor=2", "--enable-use-zoom-for-dsf=false"]
},
{
"prefix": "scalefactor150",
"base": "fast/hidpi/static",
......
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Largest Contentful Paint: contracted image bounded by display size.</title>
<style type="text/css">
#image_id {
width: 50px;
height: 50px;
}
</style>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
if (!window.LargestContentfulPaint) {
assert_unreached("LargestContentfulPaint is not implemented");
}
let beforeRender = performance.now();
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
assert_equals(entry.entryType, 'largest-contentful-paint');
assert_greater_than_equal(entry.renderTime, beforeRender,
'The rendering timestamp should occur after script starts running.');
assert_greater_than_equal(performance.now(), entry.renderTime,
'The rendering timestamp should occur before the entry is dispatched to the observer.');
assert_equals(entry.startTime, 0);
assert_equals(entry.duration, 0);
// black-rectangle.png is 100 x 50. It occupies 50 x 50 so size will be bounded by the displayed size.
assert_equals(entry.size, 2500);
assert_equals(entry.id, 'image_id');
const pathname = window.location.origin + '/images/black-rectangle.png';
assert_equals(entry.url, pathname);
assert_equals(entry.element, document.getElementById('image_id'));
})
);
observer.observe({type: 'largest-contentful-paint', buffered: true});
}, 'Largest Contentful Paint: |size| attribute is bounded by display size.');
</script>
<img src='/images/black-rectangle.png' id='image_id'/>
</body>
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Largest Contentful Paint: expanded image bounded by intrinsic size.</title>
<style type="text/css">
#image_id {
width: 300px;
height: 300px;
}
</style>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
if (!window.LargestContentfulPaint) {
assert_unreached("LargestContentfulPaint is not implemented");
}
let beforeRender = performance.now();
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
assert_equals(entry.entryType, 'largest-contentful-paint');
assert_greater_than_equal(entry.renderTime, beforeRender,
'The rendering timestamp should occur after script starts running.');
assert_greater_than_equal(performance.now(), entry.renderTime,
'The rendering timestamp should occur before the entry is dispatched to the observer.');
assert_equals(entry.startTime, 0);
assert_equals(entry.duration, 0);
// black-rectangle.png is 100 x 50. It occupies 300 x 300 so size will be bounded by the intrinsic size.
assert_equals(entry.size, 5000);
assert_equals(entry.id, 'image_id');
const pathname = window.location.origin + '/images/black-rectangle.png';
assert_equals(entry.url, pathname);
assert_equals(entry.element, document.getElementById('image_id'));
})
);
observer.observe({type: 'largest-contentful-paint', buffered: true});
}, 'Largest Contentful Paint: |size| attribute is bounded by intrinsic size.');
</script>
<img src='/images/black-rectangle.png' id='image_id'/>
</body>
# This suite runs the tests in LayoutTests/external/wpt/largest-contentful-paint/
# with the flag --force-device-scale-factor=2.
# This suite runs the tests in LayoutTests/external/wpt/largest-contentful-paint/
# with the flags --force-device-scale-factor=2 and --enable-use-zoom-for-dsf=false
# TODO(npm): Remove this virtual test when all platforms are migrated to use zoom for dsf.
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